在C#中检查泛型方法的类型参数

syn*_*tic 56 c# generics typechecking

是否有可能在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
        ...
    }
}
Run Code Online (Sandbox Code Playgroud)

Jon*_*eet 94

是:

if (typeof(T) == typeof(MyClass))
{
    MyClass mc = (MyClass)(object) t;
}
else if (typeof(T) == typeof(List<MyClass>))
{
    List<MyClass> lmc = (List<MyClass>)(object) t;
}
Run Code Online (Sandbox Code Playgroud)

您需要通过强制转换为对象,这有点奇怪,但这只是泛型工作的方式 - 没有像您预期的那样从泛型类型转换.

当然另一种选择是使用正常的执行时间检查:

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

t当然,如果为null,那将与第一个代码块的行为不同.

我会尽可能地避免使用这种代码 - 但有时候它可能是必要的,但泛型方法的想法是能够编写对任何类型都以相同方式工作的通用代码.

  • @synergetic:您已经描述了类型层次结构,但没有描述您想用它做什么。如果有用,您可以使用反射(例如`typeof(T).BaseType` 或`typeof(T).IsAssignableFrom(...)` 来探索类型层次结构。如果可能的话,我仍然会尽量避免它:) (2认同)

Sou*_*uke 8

这是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;}
}
Run Code Online (Sandbox Code Playgroud)


mar*_*iro 5

从C#7开始,您可以通过is操作员以简洁的方式执行此操作:

public void DoSomething<T>(T value)  
{
    if (value is MyClass mc)
    {
        ...
    }
    else if (value is List<MyClass> lmc)
    {
        ...
    }
}
Run Code Online (Sandbox Code Playgroud)

请参阅文档:https : //docs.microsoft.com/zh-cn/dotnet/csharp/language-reference/keywords/is#pattern-matching-with-is