Лучше, если заявление с проверкой типа C # - PullRequest
4 голосов
/ 28 июня 2019

В настоящее время я работаю над приложением .NET 4.7.1.У меня есть оператор If для проверки типа данных и соответствующего вызова метода-обработчика.

Мой текущий оператор If выглядит следующим образом:

// object msg = MyHelper.Deserialize(xmlString);

if (msg is Tomato) Handle_Tomato((Tomato)msg);
if (msg is Apple) Handle_Apple((Apple)msg);
if (msg is Banana) Handle_Banana((Banana)msg);
if (msg is Orange) Handle_Orange((Orange)msg);

msg - это в основном объект, десериализованный из строки.

Мне было интересно, есть ли лучший способ написать мои операторы if?

Большое спасибо!

Ответы [ 4 ]

8 голосов
/ 28 июня 2019

Как Sweeper упоминает в комментариях, из C # 7.0 вы можете использовать Типовое выражение типа

if (msg is Tomato tomato) Handle_Tomato(tomato);

Вы также можете использовать сопоставление с шаблоном оператора switch (тип шаблона) , начиная с C # 7.0

Шаблон типа позволяет проводить краткую оценку и преобразование типов. когда используется с оператором switch для выполнения сопоставления с образцом, он тестирует можно ли преобразовать выражение в указанный тип и, если оно может быть, преобразует его в переменную этого типа.

switch(msg)
{
   case Tomato tomato : Handle_Tomato(tomato); break;
   case Apple apple : Handle_Apple(apple); break;
   ...
}
4 голосов
/ 28 июня 2019

Я бы настоятельно рекомендовал не делать такие проверки.Что если в будущем появятся десятки разных типов?Ваше заявление if будет увеличено и будет необслуживаемым.Что если тип изменится?Вам также придется изменить все операторы if.

Вы можете решить эту проблему с помощью интерфейса.У вас уже есть классы.

interface IHandler
{
    void Execute();
} 
class Orange : IHandler 
{
    public void Execute()
    {
        // do your orange stuff 
    }
}
class Tomato : IHandler
{
    public void Execute()
    {
        // do your tomato stuff
    }
}

Это можно назвать так.

if (msg is IHandler) ((IHandler)msg).Execute();
2 голосов
/ 28 июня 2019

Я думаю, что проще всего было бы использовать switch/case

switch (msg)
{
    case Tomato t:
        Handle_Tomato(t);
        break;
    case Apple a:
        Handle_Apple(a);
        break;
    case Banana b:
        Handle_Banana(b);
        break;
    case Orange o:
        Handle_Orange(o);
        break;
}
1 голос
/ 28 июня 2019

Используйте словарь. Я предвижу, что в будущем вы будете взорваны новыми случаями, вообще говоря, стены if и большие операторы switch являются плохим кодом. В похожей ситуации я создал что-то вроде этого:

private static readonly Dictionary<RuntimeTypeHandle, Action<object>> handleMsgImplementations = new Dictionary<RuntimeTypeHandle, Action<object>>
{
    { typeof(Tomato).TypeHandle, x => Handle_Tomato((Tomato)x) },
    // etc...
};

// Then instead of if, use this (prepare a catch for Invalid Key or use a TryGetValue)
handleMsgImplementations[msg.GetType().TypeHandle](msg);

Я получаю TypeHandle, потому что мне нравится использовать тип значения для ключа.

РЕДАКТИРОВАТЬ: @TheGeneral ответ является лучшим, также, компилятор C # создает словарь под капотом, когда количество случаев начинает ухудшать производительность. Я держу свой ответ, потому что я верю, что добавляет ценность.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...