Проверка параметра типа общего метода в С#
Можно ли сделать что-то подобное в С#:
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
...
}
}
Ответы
Ответ 1
Да:
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
является нулевым, конечно.
Я попытался бы избежать такого рода кода, где это возможно, однако - иногда это может потребоваться, но идея общих методов заключается в том, чтобы писать общий код, который работает одинаково для любого типа.
Ответ 2
Это 2017, и теперь у нас есть С# 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;}
}
Ответ 3
Я считаю, что в вашем дизайне что-то не так. Вы хотите сравнить типы в уже общем методе. Generics предназначены для работы с переменной типа. Я рекомендую сделать это таким образом.
//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>
{
...
}
Ответ 4
Начиная с С# 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