为什么我不能将`this`转换为泛型?

时间:2016-07-31 04:41:41

标签: c# casting

我遇到了一个问题,为什么下面的代码段都没有编译。

Visual Studio将第一个标记为:

  

无法将'SomeType'类型转换为'T'

     

施法是多余的。

using System;

public class SomeClass {
    public T Coerce<T>() {
        if (typeof(T) == typeof(SomeClass))
            return (T)this; // <- Error CS0030
        else throw new InvalidCastException();
    }
}

然后,删除“冗余”强制转换只会将错误更改为:

  

无法将类型'SomeOtherClass'隐式转换为'T'

using System;

public class SomeOtherClass {
    public T Coerce<T>() {
        if (typeof(T) == typeof(SomeOtherClass))
            return this; // <- Error CS0029
        else throw new InvalidCastException();
    }
}

1 个答案:

答案 0 :(得分:2)

编译器告诉你到底出了什么问题:你无法隐式地将SomeClass转换为T,但实际上有两件事你需要注意。

首先,您不能隐式转换为泛型类型,因为在编译时不知道该类型。你必须明确地转换它 - 如果你真的需要隐式转换 - 使用继承。

第二件事是需要更多类型信息(通过约束)以区分值类型和引用类型。现在,编译器知道关于T。它也可能是intclass永远不会被投射到。{/ p>

为了将引用类型转换为T,您需要class约束,它将正常工作:

public class SomeClass
{
    public T Coerce<T>() where T : class
    {
        if (typeof(T) == typeof(SomeClass))
            return this as T;
        else throw new InvalidCastException();
    }
}

现在编译器也会阻止你做someClassInstance.Coerce<int>()这样的事情,这就是重点。

修改

至于(T)(object)this的示例,这是有效的,因为您不再将this投射到T。相反,您将this投射到object(这将永远有效,因为它是所有其他类型派生自的),然后您从object投射到{{ 1}}这也是出于同样的原因。您正在规避编译时检查。

您可以执行此操作然后调用T,它会为您提供异常“指定的强制转换无效”。在运行时。但是,使用通用约束会在编译时时为您提供警告。

如果这不打扰你,someClassInstance.Coerce<int>()是一个更简单的解决方案。但这有点违背了使用泛型的目的。