C#10 - использование типа T для переключения универсального метода

Есть много ответов о том, как включить тип в старых версиях C#. Мой вопрос связан с тем, как включить тип, вызываемый в универсальном методе:

          public T GetAxis<T>(object axisObject)
    {
        switch (typeof(T))
        {
            case Axis:
                //...do something
                break;
        }

        return null;
    }

Я получаю сообщение об ошибке в строке:

      case Axis axis:

Ошибка:

Выражение типа System.Type не может обрабатываться шаблоном типа MyNamespace.Axis.

Я считаю, что мой вопрос в том, как мне вызвать Type, который вызывается в спецификации <>, чтобы я мог его включить.

2 ответа

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

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

Вместо:

      var axis = GetAxis<Axis>(axisObject);
var somethingElse = GetAxis<SomethingElse>(axisObject);

Использовать:

      var axis = GetAxis(axisObject);
var somethingElse = GetSomethingElse(axisObject);

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

      public T GetAxis<T>(object axisObject)
{
    switch (axisObject)
    {
        case Axis axis:
            //...do something with `axis`
            break;
        case SomethingElse somethingElse:
            //...do something with `somethingElse`
            break;
    }

    return default;
}

В этом последнем случае мне неясно, какое значение универсальный тип имеет: вы можете заменить его неуниверсальным возвращаемым типом.

Имея дело с подобными вещами, я обычно прибегаю к следующему словарю:

      private Dictionary<Type, Delegate> _axisCases = new Dictionary<Type, Delegate>();

Вы можете написать такой код вокруг него:

      public class MyCode
{
    public MyCode()
    {
        this.SetCase<Axis>(o => new Axis());
    }
    
    private Dictionary<Type, Delegate> _axisCases = new Dictionary<Type, Delegate>();

    private void SetCase<T>(Func<object, T> func)
    {
        _axisCases[typeof(T)] = func;
    }

    public T GetAxis<T>(object axisObject) where T : class
    {
        var t = typeof(T);
        if (_axisCases.ContainsKey(t))
        {
            var func = (Func<object, T>)_axisCases[t];
            return func(axisObject);
        }
        return null;
    }
}

Теперь вы можете назвать это так:

      var myCode = new MyCode();
var axis = myCode.GetAxis<Axis>(new object());

Этот тип кода является наиболее гибким. Но если вы хотите что-то более близкое к обычному оператору case

Другие вопросы по тегам