Чистый код, примененный к .NET: избежать проверки типов с помощью сопоставления с образцом, связано с проблемой производительности?

2

Я читал Github-репозиторий о концепциях чистого кода, применяемых к С#, и был удивлен, что стратегия сопоставления с образцом рекомендована для того, чтобы избежать проверки типов (в дополнение https://github.com/thangchung/clean-code-dotnet# Во избежание типа проверки частей-1

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

Пример, используемый в этом хранилище:

// Bad: btw this example cannot even work, the methods are not defined in Object. Going to fork and PR.
public Path TravelToTexas(object vehicle)
{
    if (vehicle.GetType() == typeof(Bicycle)) 
    {
        vehicle.PeddleTo(new Location("texas"));
    } 
    else if (vehicle.GetType() == typeof(Car)) 
    {
        vehicle.DriveTo(new Location("texas"));
    }
}

// Good: parent class / interface
public Path TravelToTexas(Traveler vehicle)
{
    vehicle.TravelTo(new Location("texas"));
}

or

// Good: pattern matching
public Path TravelToTexas(object vehicle)
{
    if (vehicle is Bicycle bicycle)
    {
        bicycle.PeddleTo(new Location("texas"));
    } 
    else if (vehicle is Car car) 
    {
        car.DriveTo(new Location("texas"));
    }
}

За исключением того, что switch сопоставления с образцом /is переводится во что-то эквивалентное if/else if/else с использованием оператора is (переводится как obj as TargetType != null) + некоторые условия (и тот факт, что вам не нужно объявлять некоторые переменные заранее).

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

И выдержка из: https://docs.microsoft.com/en-us/dotnet/csharp/pattern-matching#when-clauses-in-case-expressions

Чтобы проиллюстрировать эти новые идиомы, давайте работать со структурами, которые представляют геометрические фигуры, используя операторы сопоставления с образцом. Вы, вероятно, знакомы с построением иерархий классов и созданием виртуальных методов и переопределенных методов для настройки поведения объекта в зависимости от типа объекта во время выполнения.

Эти методы невозможны для данных, которые не структурированы в иерархии классов. Когда данные и методы разделены, вам нужны другие инструменты. Новые конструкции сопоставления с образцом позволяют использовать более чистый синтаксис для проверки данных и управления потоком управления на основе любого состояния этих данных. Вы уже пишете операторы if и переключаете это тестирование значения переменной. Вы пишете это заявления, которые проверяют тип переменной. Сопоставление с образцом добавляет новые возможности к этим утверждениям.

Например, вместо этого невозможно использовать шаблон адаптера и в основном обернуть объекты третьей стороны во что-то, над чем вы можете иметь контроль. Я имею в виду, за исключением смертельного случая, чтобы получить неинформативный object я не вижу смысла делать это.

Теги:
pattern-matching

1 ответ

1
Лучший ответ

(переводится как obj as TargetType != null)

Хорошо, это не совсем правильно. Проверьте пример на MSDN.

Старый способ:

public static double ComputeArea(object shape)
{
    if (shape is Square)
    {
        var s = (Square)shape;
        return s.Side * s.Side;
    } 
    else if (shape is Circle)
    {
        var c = (Circle)shape;
        return c.Radius * c.Radius * Math.PI;
    }
    // elided
    throw new ArgumentException(
        message: "shape is not a recognized shape",
        paramName: nameof(shape));
}

Обратите внимание на явное приведение. Теперь версия С# 7.0:

public static double ComputeAreaModernIs(object shape)
{
    if (shape is Square s)
        return s.Side * s.Side;
    else if (shape is Circle c)
        return c.Radius * c.Radius * Math.PI;
    else if (shape is Rectangle r)
        return r.Height * r.Length;
    // elided
    throw new ArgumentException(
        message: "shape is not a recognized shape",
        paramName: nameof(shape));
}

Так что изменилось? Ну, старый способ, которым вы должны были: 1) привести объект и 2) использовать явное приведение в случае типов значений. То есть использование as для типа значения было исключением. Теперь is ключевое слово обновляется здесь, чтобы бросить и присвоить переменной, но она также обрабатывает типы значений (не используется, as за кулисами). Это делает код немного более лаконичным/простым в обслуживании. Или, по словам MSDN

В этой обновленной версии выражение is одновременно проверяет переменную и присваивает ее новой переменной правильного типа. Также обратите внимание, что эта версия включает тип Rectangle, который является struct. Новое is выражение работает с типами значений, а также ссылочных типов.

Возможно, только небольшое преимущество, но в документации MSDN указывается, что новый объект ограничен по объему, в зависимости от оператора if. Возможно, вы уже делали это раньше (приведение внутри блока if), но теперь это происходит автоматически.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню