Как вы используете `switch` в C # для условного перехода только на основе параметра типа? - PullRequest
1 голос
/ 09 апреля 2019

Мой контекст заключается в том, что я создаю простой фабричный метод для создания экземпляров производных типов данного базового типа.Фабричный метод принимает только параметр типа, т.е. не имеет аргументов.Это очевидно возможно с помощью конструкции if - else if:

public Vehicle Create<T>()
{
    if (typeof(T) == typeof(Car))
        return new Car(); // just an example; could be more complex logic.
    else if (typeof(T) == typeof(Truck))
        return new Truck(); // just an example; could be more complex logic.
    else
        throw new ArgumentException(
            $"The type {typeof(T).Name} is not known by this method.");
}

На данный момент хорошо известно, как использовать сопоставление с образцом в C # (начиная с C # 7.0) для перехода на основе типа переменная , но это не работает для параметра типа:

switch (T) { ... } // error: "'T' is a type, which is not valid in the given context"

или ...

switch (typeof(T))
{
    case Car c: ... 
    // err: "An expression of type 'Type' cannot be handled by a pattern of type 'Car'"
}

Так что я хотел бы знать если можно использовать switch для достижения того же результата?


Исследование: Я удивлен, что об этом раньше не спрашивали, но я не могу его найти.Я нашел этот пост , в котором есть имя и несколько ответов, которые довольно близки, но он имеет дело с (числовыми) типами значений и методами, которые имеют аргумент типа T - параметр универсального типа.Точно так же этот пост также использует аргумент.

Ответы [ 2 ]

1 голос
/ 11 апреля 2019

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

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

public class Car : Vehicle { }
public class Truck : Vehicle { }

public abstract class Vehicle
{
    private static readonly IReadOnlyDictionary<Type, Func<Vehicle>> vehicleFactories = new Dictionary<Type, Func<Vehicle>>
    {
        { typeof(Car), () => new Car() },
        { typeof(Truck), () => new Truck() }
    };

    public static Vehicle Create<T>() where T : Vehicle, new()
    {
        if (vehicleFactories.TryGetValue(typeof(T), out var factory))
        {
            return factory();
        }
        else
        {
            throw new ArgumentException(
                $"The type {typeof(T).Name} is not known by this method.");
        }
    }
}
0 голосов
/ 09 апреля 2019

РЕДАКТИРОВАТЬ: Обратите внимание, что я не делаю никаких заявлений о том, хорошо это или плохо.Это полностью показывает, что это возможно.

Это можно сделать в C # 7.0 или более поздней версии, используя блок switch с сопоставлением с шаблоном и ключевое слово when:

public Vehicle Create<T>() where T : Vehicle
{
    switch (true)
    {
        case bool x when typeof(T) == typeof(Car): return new Car();
        case bool x when typeof(T) == typeof(Truck): return new Truck();
        default: throw new ArgumentException(
            $"The type {typeof(T).Name} is not known by this method.");
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...