2015-10-06 219 views
4

我在C#中的类型推断中发现了一些奇怪的东西。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'

如果我写as

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 ()'并得到异常。编译器*信任你当你做类型转换'(T)(IInterface1)',但运行时不会 – ASh

回答

8

这是为了防止自己在脚下射击。就像你设法最终做的一样。

如果你定义

interface IInterface2 : IInterface1 { } 

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

更糟糕的是,如果你定义

class Class2 : IInterface1 { } 

,然后发生了什么叫GetSomething<Class2>()

你的设计被破坏了,你需要多思考一下,而不是继续解决编译错误,直到你有一个实际上有工作机会的设计。

3

您的类型参数T保证执行IInterface1,但它与Class1的关系未指定。

因此:

  1. Ť可能不是一个超类的Class1并且还Class1可能不是一个超类的T =>(T)GetInstanceOfClass1()失败
  2. 不能返回来自方法的IInterface那返回T =>(IInterface1)GetInstanceOfClass1()失败

的一个工程:

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

E.g.

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

这是编译,但在运行时失败。