2014-11-18 2 views
0

Возможно ли создать оператор switch-case вокруг EventArgs?Корпус коммутатора типов EventArg

т.е. .:

void MyMethod(object sender, EventArgs e) 
{ 
    switch(e) 
    { 
     //MyEventArgs inherit from EventArgs 
     case e is MyEventArgs: 
      //Do some code... 
      break; 
     default: 
      break; 
    } 
} 

Прямо сейчас я не могу найти способ, чтобы поместить его в распределительном регистре, поэтому я использую if-то еще заявления, который будет медленнее, чем комму- когда я заполняю многие if-else в нем (поскольку в случае с коммутатором создается какая-то хэш-таблица футляра под капотом).

+1

Вы действительно не заметите разницы в скорости. –

+0

Является ли ваша цель выполнять код только тогда, когда пользовательский объект EventArgs будет передан вашему методу? Я имею в виду ... Есть ли какой-либо нестандартный объект EventArgs, который требует выполнения кода в этом случае? – HuorSwords

+0

Сколько классов вы получили от 'EventArgs'? Кажется, что из предыдущих ответов консенсус заключается в том, что вам понадобится полдюжины отчетов о случаях, чтобы работать лучше, чем 'if', и даже тогда это незначительно, пока вы не будете иметь дело с очень большими цифрами. –

ответ

3

Вы не можете использовать switch в вашем сценарии.

switch заявление требует целостного типа или строки в качестве параметра (подробнее см. Ниже). Вы не можете передать EventArgs в качестве параметра в оператор switch. Также оператор case требует значения постоянной времени компиляции.

Если вы посмотрите на C# 5.0 Specifications:

Тип управляющих переключателя заявления устанавливается выражения переключателя.

  • Если тип выражения переключатель SByte, байт, короткие, USHORT, INT, UINT, длинные, ULONG, BOOL, символ, строка или перечисление типа, или если он является обнуляемым тип соответствующий одному из этих типов, то
    является управляющим типом оператора switch.
  • В противном случае, ровно один определенный пользователем неявное преобразование (§6.4) должна существовать от типа выражения коммутатора к одному из следующих
    возможных типов управляющих: SByte, байт, короткие, UShort, INT, UINT,
    long, ulong, char, string, или, тип с нулевым значением, соответствующий одному
    этих типов.
  • В противном случае, если такое неявное преобразование не существует или существует более одного такого неявного преобразования, возникает ошибка времени компиляции .

Другой вопрос в коде является сазе:

switch C#

Каждый случай метка указывает на постоянное значение.

Оператор case указывает значение, которое невозможно определить во время компиляции.

Это дает вам возможность использовать блок if-else. Если вы не обрабатываете сотни типов EventArgs, маловероятно, что вы увидите значительное увеличение производительности.

+0

Thats смысл. Наверное, я оставлю его с инструкцией if-else. Я занимаюсь только 4-5 различными EventArgs atm, но могу использовать более позднее. Я предполагаю, что если я действительно захочу положить его в коммутационный футляр, я бы мог обернуть пользовательские eventargs и дать ему значение Enum для case вместо. Но тогда if-else будет более аккуратным в любом случае. Благодарю. – grmihel

+0

@grmihel, также, насколько я помню, для числа случаев ниже 5 в инструкции switch компилятор не создает таблицу поиска. Вы также можете подумать о перепроектировании своего решения, так как это выглядит как запах кода. – Habib

+0

Я не уверен, что редизайн необходим. Метод догоняет события, которые затем определяют, какой ответ отправить. Конечно, если количество событий резко возрастает, я должен разбить его на peices :) – grmihel

3

В корпусе блока выключателей каждый случай должен быть оценен статически. Это означает, что вам нужна константа в каждом случае. Это сообщение может быть полезно также C# switch statement limitations - why?

0

только для полноты картины, это будет работать, но вы должны НЕ сделать это, по причинам, которые должны быть весьма очевидны:

void MyMethod(object sender, EventArgs e) 
{ 
    switch(e.GetType().FullName) 
    { 
     case "MyNamespace.MyEventArgs": 
      //seriously, don't do this. 
      break; 
     case "System.EventArgs": 
      //this is the worst idea ever. 
      break; 
     default: 
      break; 
    } 
} 
+0

Мы думали одинаково, но это было бы ДЕЙСТВИТЕЛЬНО уродливой реализацией его, но, конечно же, это сработало бы, если бы вы вдруг не испортили пространства имен :) – grmihel

+0

Реализовать его таким образом назначил бы вас на место на http://thedailywtf.com/ – Rotem

1

Вы можете попробовать его с Dictionary<Type, Action<EventArgs>>:

private static Dictionary<Type, Action<EventArgs>> _EventDispatcher; 

static Program() 
{ 
    _EventDispatcher = new Dictionary<Type, Action<EventArgs>>(); 
    _EventDispatcher.Add(typeof(EventArgs), OnEventArgs); 
    _EventDispatcher.Add(typeof(MyEventArgs), OnMyEventArgs); 
} 

private static void MyMethod(object sender, EventArgs e) 
{ 
    Action<EventArgs> eventMethod; 

    if (!_EventDispatcher.TryGetValue(e.GetType(), out eventMethod)) 
     eventMethod = OnUnknownEventArgs; 

    eventMethod(e); 
} 

private static void OnEventArgs(EventArgs e) 
{ 
    Console.WriteLine("Simple event args: " + e); 
} 

private static void OnMyEventArgs(EventArgs e) 
{ 
    var myEventArgs = (MyEventArgs)e; 
    Console.WriteLine("My event args: " + myEventArgs); 
} 

private static void OnUnknownEventArgs(EventArgs e) 
{ 
    Console.WriteLine(String.Format("Unknown event args ({0}): {1}", e.GetType(), e); 
} 

private static void Main(string[] args) 
{ 
    MyMethod(null, new EventArgs()); 
    MyMethod(null, new MyEventArgs()); 
    MyMethod(null, new AnotherEventArgs()); 

    Console.ReadKey(); 
} 
1

вы подумали об использовании метода перегрузок вместо этого? обычно говорил, что я постараюсь избежать блокировки блоков блокировки с исключениями вида, так как они часто являются запахом, что наследование, перегрузки и т. Д. Могут решить проблему лучше.

BR

+0

Звучит интересно. Не могли бы вы привести пример этого? – grmihel

+0

простой метод перегрузки для каждого типа EventArgs, который вы хотите обработать: 'void MyMethod (object sender, MyEventArgs e) {/ * сделать код * /} .... void MyMethod (object sender, MyOtherEventArgs e) {/ * сделать какой-то другой код * /} 'таким образом, чтобы вы могли избежать блока case swith, потому что типы разделены сигнатурой метода. конечно, вы всегда можете слишком усложнять ситуацию, поэтому вам нужно определить, подходит ли sthg в вашем конкретном коде. однако, я всегда рассматриваю корпус коммутатора как запах и грубо смотрю, если sthg необходимо реорганизовать – Matthias

Смежные вопросы