为什么必须在某些通用情况下进行投射?

时间:2015-10-08 20:38:27

标签: c# generics

在通用方法中,您需要将返回变量强制转换为对象,然后返回到泛型类型,我理解为什么通常这样,但是我不明白为什么当您需要时,为什么需要这样做? #39;已经确定了变量在return语句范围内的类型。例如,通常我会这样做:

public MyType1 obj1;
public MyType2 obj2;

public T GetObject<T>()
{
    if (obj1 is T) return (T)(object)obj1;
    else if (obj2 is T) return (T)(object)obj2;
    else return default(T);
}

但我的问题是,为什么我不能像这样删除演员:

public MyType1 obj1;
public MyType2 obj2;

public T GetObject<T>()
{
    if (obj1 is T) return obj1;
    else if (obj2 is T) return obj2;
    else return default(T);
}

为什么编译器不能理解该对象是唯一的类型?

3 个答案:

答案 0 :(得分:3)

您对泛型做出了错误的假设。为了更好地理解这一点,想象一下。假设您有一个基类Base和两个子类Sub和VerySub。

如果您的成员存储为Base,则编译器只能保证它们是Base。它是泛型使用的静态打字系统。在运行时,让我们说我们有一个名为GetIfVerySub的简单函数。让我们说它对Base类型的对象进行了测试,并发现它也是一个VerySub。这在编译时是不可知的,所以为了返回下载的对象,你会期望做一个演员或一个as。

这正是你的泛型函数正在尝试做的事情,但由于它是通用的,它也可以在任何类型上工作,包括与Base不兼容的类型。

但更好的问题是你为什么要这样做?

答案 1 :(得分:3)

根据C# Reference

  

关键字会导致编译时警告,如果已知表达式始终为 true 或始终为 false ,但通常在运行时评估类型兼容性。

这是obj1类型T是否由编译器确定,但在代码运行时进行评估。

答案 2 :(得分:1)

避免使用foo is T; (T)foo个表达式。使用as运算符可以解决您的问题:

public MyType1 obj1;

public T GetObject<T>() where T : class {
    T ret = obj1 as T;
    if( ret != null ) return ret;
    ret = obj2 as T;
    if( ret != null ) return ret;
    return default(T);
}