รายการการกระทำ / ฟังก์ชั่น C #

ฉันมีโปรแกรมที่ต้องรันฟังก์ชันตาม Enum และฉันสงสัยว่ามีวิธีอื่นนอกเหนือจากนี้หรือไม่:

enum FunctionType
{
 Addition = 0,
 Substraction = 1,
 Mutiplication = 2,
 Division = 3
}
void ExecuteFunction(FunctionType Function)
{
  switch(Function)
  {
    case FunctionType.Addition: Addition();
    break;
    case FunctionType.Substraction: Subsctration();
    break;      
    ...
    default: ...  
  }
}

(นี่ไม่ใช่รหัสที่ฉันใช้ แต่เป็นเพียงเพื่อแสดงสิ่งที่ฉันต้องการทำ) วิธีการนี้น่าจะได้ผลดี แต่จะเกิดอะไรขึ้นเมื่อคุณมีฟังก์ชันมากกว่านี้อีกมาก? ฉันไม่อยากมีสวิตช์ 50 เส้น ผมอยากทราบว่ามีวิธีทำให้มันง่ายขึ้นหรือเปล่า อะไรประมาณนี้:

enum FunctionType : Action
{
 Addition = new Action(Addition);
 Substraction = new Action(Substraction);
 ....
}
void ExecuteFunction(FunctionType Function)
{
 (Action)Function.Invoke();
}

ไม่จำเป็นต้องใช้สวิตช์ และสิ่งที่อาจเป็น 50 บรรทัดก็จะกลายเป็น 1 บรรทัด แต่ทำไม่ได้ มีเพียงประเภทตัวเลขเท่านั้นที่ยอมรับเป็นแจงนับ ฉันคิดว่าเป็นไปได้ที่จะมีการกระทำ List<T> แต่จะต้องเพิ่มแต่ละการกระทำลงในรายการในขณะรันไทม์

แก้ไข: ฉันพบวิธีการในซอร์สโค้ดแล้ว แต่ฉันไม่เข้าใจมันจริงๆ นี่คือสิ่งที่ฉันได้รับ: พวกเขาสร้าง Attribute แบบกำหนดเองที่มี string (ชื่อวิธีการ) และในวิธีการที่พวกเขาทำ:

[CustomAtrribute("name")]
void Method()
{    
}

ถ้าอย่างนั้นฉันก็ไม่รู้ว่าชื่อนี้ถูกเรียกอย่างไร ฉันเดาว่ามันคงเป็นความรู้สึกบางอย่าง แต่ฉันไม่รู้ว่าจะหาข้อมูลเกี่ยวกับเรื่องนี้ได้อย่างไร

แก้ไข 2: ฉันพบวิธีที่ฉันต้องการทำสิ่งนี้ ฉันจะเพิ่มอินเทอร์เฟซพร้อมฟังก์ชัน จากนั้นใช้อินเทอร์เฟซนั้นกับโค้ดภายในฟังก์ชัน และใช้ Dictionary<Enum, Interface> เพื่อเรียกมัน ฉันไม่รู้ว่าฉันควรตอบคำถามของตัวเองดีหรือไม่ ขอบคุณทุกคนที่ช่วยฉัน


person Pau C    schedule 19.08.2016    source แหล่งที่มา
comment
คุณสามารถมี Dictionary<FunctionType, Action>... แต่อีกครั้ง คุณจะต้องสร้างมันขึ้นมาในเวลาดำเนินการ หากชื่อวิธีการทั้งหมดตรงกับชื่อค่า enum คุณสามารถทำได้ผ่านการไตร่ตรอง   -  person Jon Skeet    schedule 19.08.2016
comment
คุณสามารถดำเนินการได้โดยการต่อท้าย () โดยไม่จำเป็นต้องทำ .Invoke() แค่ไฟนี่   -  person vrwim    schedule 19.08.2016
comment
@Jon Skeet บางทีพจนานุกรมอาจใช้งานได้ดี แต่การเพิ่มทุกอย่างฟังดูไม่ดี ยังดีกว่าสวิตช์ขนาดยักษ์ การทำให้ชื่อเมธอดทุกชื่อตรงกับชื่อแจงนับทุกชื่ออาจดูอันตรายเล็กน้อยเมื่อเพิ่มสิ่งใหม่   -  person Pau C    schedule 19.08.2016
comment
แน่นอนคุณสามารถเพิ่มการทดสอบหน่วยได้ ท้ายที่สุดแล้ว คุณไม่ได้แจ้งให้เราทราบว่าทำไมคุณถึงต้องเริ่มต้นด้วยการแจงนับ เหตุใดวิธี ExecuteFunction ของคุณจึงไม่เพียงแค่ใช้ Action หรืออะไรก็ตาม   -  person Jon Skeet    schedule 19.08.2016
comment
ฉันต้องการทำสิ่งนี้บนเซิร์ฟเวอร์ และแต่ละค่าใน enum สอดคล้องกับแพ็กเก็ตประเภทอื่น แต่ละแพ็กเก็ตจะถูกระบุด้วยค่า int และแยกวิเคราะห์เป็น Enum ด้วยแพ็กเก็ตที่แตกต่างกันสองสามประเภท สวิตช์ก็น่าจะใช้ได้ แต่เมื่อฉันอัปเดตโปรแกรม ฉันต้องการเพิ่มแพ็กเก็ตเพิ่มเติม และฉันต้องการให้โค้ดสะอาด ไม่ใช่สวิตช์ขนาด 50 ตัว   -  person Pau C    schedule 19.08.2016
comment
การแยกวิเคราะห์ enum อย่างระมัดระวังอาจเป็นเรื่องยุ่งยาก: stackoverflow.com/questions/28219215/   -  person argyle    schedule 19.08.2016
comment
ฉันแค่ส่งมันจาก int และฉันตรวจสอบก่อนว่ามีค่าอยู่หรือไม่ แต่ขอบคุณ.   -  person Pau C    schedule 19.08.2016


คำตอบ (2)


ไม่สามารถพูดได้ว่าฉันอยากจะแนะนำให้ทำเช่นนี้ แต่:

public static class Functions
{
    public static Func<int, int, int> Add = (x, y) => { return x + y; };
}

จากนั้นคุณก็โทร Functions.Add(1,1)

หากคุณ มี ต้องใช้ enum จริงๆ คุณก็สามารถทำได้:

public static class Functions
{
    public static void Add()
    {
        Debug.Print("Add");
    }

    public static void Subtract()
    {
        Debug.Print("Subtract");
    }

    public enum Function
    {
        Add,
        Subtract
    }

    public static void Execute(Function function)
    {
        typeof(Functions).GetMethod(function.ToString()).Invoke(null, null);
    }
}

จากนั้น Functions.Execute(Functions.Function.Add) (ฟังก์ชันพิเศษเป็นเพราะ enum ของฉันอยู่ในคลาส Functions)

person Dave Williams    schedule 19.08.2016
comment
สิ่งนี้ดูน่าสนใจ แต่จะส่งผลต่อประสิทธิภาพเมื่อมีการเรียกหลายครั้งหรือไม่ แล้วทำไม .Invoke(null, null);? - person Pau C; 19.08.2016
comment
ฉันทดสอบสิ่งนี้แล้วและผลกระทบต่อประสิทธิภาพค่อนข้างมาก จะต้องใช้เวลา x30 ถ้าฉันป้อนฟังก์ชันชื่อเป็นสตริงและ x133 ถ้าฉันทำ .ToString() เปรียบเทียบการเรียกใช้ฟังก์ชันปกติ ถ้าฉันโหลด methodInfo ก่อนมันจะต้องใช้เวลา x20 - person Pau C; 19.08.2016
comment
@null .Invoke(null,null) เพื่อเรียกวิธีคงที่โดยไม่มี args คุณอาจต้องเปลี่ยนมันเพื่อสิ่งของคุณ ประสิทธิภาพการใช้การสะท้อนจะได้รับผลกระทบอย่างมาก ฉันบอกว่าฉันแนะนำว่าอย่าทำ มันอาจจะคุ้มค่าที่จะพิจารณาว่าคุณกำลังทำสิ่งที่ถูกต้องหรือไม่หากคุณรู้สึกว่าจำเป็นต้องไตร่ตรอง ฉันสามารถตอบคำถามของคุณได้เพียงเพราะฉันไม่รู้ว่าคุณกำลังพยายามทำอะไรให้สำเร็จ ทั้งหมดที่กล่าวมา การลงโทษตามผลงานอาจยอมรับได้ขึ้นอยู่กับสถานการณ์ของคุณ อย่าเพิ่มประสิทธิภาพก่อนเวลาอันควร - person Dave Williams; 21.08.2016
comment
ฉันพบวิธีที่จะทำสิ่งที่ฉันต้องการ ฉันตั้งค่าแอตทริบิวต์ที่กำหนดเองด้วยสตริงให้กับฟังก์ชัน จากนั้นฉันใช้การสะท้อนเพื่อรับฟังก์ชันทั้งหมดที่มีคุณลักษณะนั้น และเพิ่มลงใน Dictionary‹string, ผู้รับมอบสิทธิ์› ดังนั้นจึงมีไม่มากขนาดนั้น ส่งผลต่อประสิทธิภาพ เนื่องจากฉันใช้การสะท้อนเพียงครั้งเดียว - person Pau C; 22.08.2016

หากฟังก์ชันของคุณมี signature เหมือนกัน คุณสามารถทำสิ่งนี้ได้

enum FunctionType
{
 Addition = 0,
 Substraction = 1,
 Mutiplication = 2,
 Division = 3
}
void ExecuteFunction(FunctionType Function)
{
  //variable will contain function to execute
  public Func<int, int, int> functionToExecute= null;

  switch(Function)
  {
    case FunctionType.Addition: functionToExecute=Addition;
    break;
    case FunctionType.Substraction: functionToExecute=Subsctration;
    break;      
    ...
    default: ...  
  }

  //Checking if not reached default case
  if(functionToExecute!=null)
  {
   var result= functionToExecute(para1,para2);
   ...............
  }


}
person Moumit    schedule 19.08.2016
comment
ฉันกำลังพยายามหลีกเลี่ยงการเปลี่ยน นั่นคือปัญหาตั้งแต่แรก ถ้าฉันมีฟังก์ชั่นมากมาย โค้ดก็จะยาวเกินไป - person Pau C; 19.08.2016