C# 类型推断、泛型和接口

4

在C#中的类型推断中,我发现了一些奇怪的问题。

下面是一个例子:

我有一个接口

interface IInterface1
{
}

并且实现接口的类

class Class1 : IInterface1
{
}

接下来我有一个创建类的函数

static Class1 GetInstanceOfClass1()
{
    return new Class1();
}

我想使用通用函数,它将返回一个可枚举对象。

static IEnumerable<T> GetSomething<T>() where T : IInterface1
{
    yield return GetInstanceOfClass1();
}

完整的代码如下:
using System.Collections.Generic;

namespace TypeInference
{
    interface IInterface1
    {
    }

    class Class1 : IInterface1
    {
    }

    class Program
    {
        static Class1 GetInstanceOfClass1()
        {
            return new Class1();
        }

        static IEnumerable<T> GetSomething<T>() where T : IInterface1
        {
            yield return GetInstanceOfClass1();
        }

        static void Main(string[] args)
        {
        }
    }
}

这段代码没有被编译

无法隐式将类型 'TypeInference.Class1' 转换为 'T'

如果我这样写:

yield return (T)GetInstanceOfClass1();

错误信息如下:

无法将类型“TypeInference.Class1”转换为“T”

之前的转换无法继续进行。
好的,我写成这样。
yield return (IInterface1)GetInstanceOfClass1();

并且得到

无法将类型'TypeInference.IInterface1'隐式转换为'T'

就像之前一样,它无法转换。

但是如果我写成

yield return (T)(IInterface1)GetInstanceOfClass1();

一切都没问题。

有人能解释一下为什么代码最终编译成功了吗?

谢谢。


1
无法保证(T)(IInterface1)GetInstanceOfClass1();在运行时不会出错。一个人可以创建class NewClass1 : IInterface1; 调用GetSomething<NewClass1>()并获得异常。编译器在进行类型转换(T)(IInterface1)信任您,但运行时不会这样。 - ASh
2个回答

8

这是为了防止你自己一不小心就出现错误。就像你现在已经做过的那样。

如果你定义

interface IInterface2 : IInterface1 { }

然后调用 GetSomething<IInterface2>()? 这是一个有效的泛型类型参数,但是 Class1 没有实现 IInterface2

更糟糕的是,如果您定义了

class Class2 : IInterface1 { }

然后调用GetSomething<Class2>()

您的设计有问题,需要再考虑一下,不要继续在编译器错误周围工作,直到您拥有一个实际有机会工作的设计。


3

您的类型参数T被保证实现了接口IInterface1,但它与Class1的关系未指定。

因此:

  1. T可能不是Class1的超类,同时Class1也可能不是T的超类 => (T)GetInstanceOfClass1() 失败
  2. 您无法从返回T的方法中返回IInterface => (IInterface1)GetInstanceOfClass1() 失败

正确的做法:

当然您可以将Class1强制转换为IInterface,因为Class1实现了该接口。 由于T也实现了IInterface,因此这可能是一个有效的转换,或者在运行时可能会失败。 这类似于您可以在编译时将任何对象转换为给定类型,但如果对象的运行时类型错误,则会在运行时失败。

例如:

object o;
o = 5;
string s = (string)o;

这个代码可以编译通过,但在运行时失败。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接