Проверка параметра типа универсального метода в C # - PullRequest
53 голосов
/ 05 января 2010

Возможно ли сделать что-то подобное в C #:

public void DoSomething<T>(T t)  
{
    if (T is MyClass)
    {
        MyClass mc = (MyClass)t 
        ...
    }
    else if (T is List<MyClass>)
    {
        List<MyClass> lmc = (List<MyClass>)t
        ...
    }
}

Ответы [ 4 ]

91 голосов
/ 05 января 2010

Да

if (typeof(T) == typeof(MyClass))
{
    MyClass mc = (MyClass)(object) t;
}
else if (typeof(T) == typeof(List<MyClass>))
{
    List<MyClass> lmc = (List<MyClass>)(object) t;
}

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

Конечно, другой альтернативой является использование обычной проверки времени выполнения:

MyClass mc = t as MyClass;
if (mc != null)
{
    // ...
}
else
{
    List<MyClass> lmc = t as List<MyClass>;
    if (lmc != null)
    {
        // ...
    }
}

Это будет вести себя иначе, чем первый блок кода, если t, конечно, равно нулю.

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

8 голосов
/ 05 мая 2017

Сейчас 2017 год, и теперь у нас есть C # 7 с сопоставлением с образцом. Если ваш тип T наследует object, вы можете написать такой код

void Main()
{
    DoSomething(new MyClass { a = 5 });
    DoSomething(new List<MyClass> { new MyClass { a = 5 }, new MyClass { a = 5 }});
}


public void DoSomething(object t)
{
    switch (t)
    {
        case MyClass c:
            Console.WriteLine($"class.a = {c.a}");
            break;
        case List<MyClass> l:
            Console.WriteLine($"list.count = {l.Count}");
            break;
    }
}

class MyClass
{
    public int a { get; set;}
}
4 голосов
/ 24 ноября 2017

Начиная с C # 7, вы можете сделать это кратко с помощью оператора is:

public void DoSomething<T>(T value)  
{
    if (value is MyClass mc)
    {
        ...
    }
    else if (value is List<MyClass> lmc)
    {
        ...
    }
}

См. Документацию: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/is#pattern-matching-with-is

3 голосов
/ 05 января 2010

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

//Generic Overload 1
public void DoSomething<T>(T t)
    where T : MyClass
{
    ...
}

//Generic Overload 2
public void DoSomething<T>(T t)
    where T : List<MyClass>
{
    ...
}
...