使用泛型和类继承键入方法的推断

时间:2011-11-02 14:02:57

标签: c# generics inheritance c#-4.0 type-inference

我有一个类层次结构,如下所示:

class Base<TElement>
{
    public TElement Element { get; set; }
}

class Concrete : Base<string>
{
}

我想编写一个接受Base子类的方法:

public TConcrete DoSomething<TConcrete, TElement>()
    where TConcrete : Base<TElement>
{
}

有没有办法定义DoSomething,而无需定义TElement

理想的解决方案是,如果编译器可以自动计算TElement,那么调用代码将如下所示:

var item = DoSomething<Concrete>();

我正在使用C#4.0。

3 个答案:

答案 0 :(得分:4)

由于以下原因,这是不可能的:

  1. 从C#4开始,类型推断是“全有或全无” - 编译器不能推断出一些通用参数而不能推断其他参数。
  2. 从C#4开始,无法指定通用的“通配符”,例如where TConcrete : Base<???>
  3. 以下是一些解决方法。

    非通用基类型:创建泛型的基类或接口类型。这是一种常见的模式;例如IEnumerable<T> : IEnumerable


    协变接口:使用C#4通用接口协方差,您可以创建一个类型安全的解决方案,不需要使用“丑陋”的非通用成员来混乱您的类型:

    public interface IBase<out TElement>
    {
        TElement Element { get; }
    }
    
    class Base<TElement> : IBase<TElement>
    {
        public TElement Element { get; set; }
    }
    
    class Concrete : Base<string>  {  }
    

    然后:

    // Won't work with value types.
    public TConcrete DoSomething<TConcrete>()
        where TConcrete : IBase<object> { }
    

    并称之为:

    var item = DoSomething<Concrete>();
    

答案 1 :(得分:1)

如果使Base继承非泛型类或实现非泛型接口,则可以将方法限制为该类型。

否则,不。如果可能的话,方法中的TConcrete.Element属性将没有类型 如果你写

会发生什么
public TConcrete DoSomething<TConcrete>() where TConcrete : Base<>   //Illegal!
{
    TConcrete c = ...;
    var b = c.Element;    //What type is that variable?
}

答案 2 :(得分:0)

如果DoSomething不知道(或关心)TElement是什么,您可能希望在没有type参数的情况下创建父类:

class Base
{
}

class Base<TElement> : Base
{
    public TElement Element { get; set; }
}

然后,您的DoSomething方法将在类Base上运行。

如果DoSomething需要知道类型参数,那么不,没有办法做你想要的事情&amp;你需要提供它。