从基类方法返回派生类型

时间:2017-04-06 21:01:04

标签: c# generics

我有一个类似于这个的类层次结构:

public class Base
{
    private List<string> attributes = new List<string>();

    public T WithAttributes<T>(params string[] attributes)
        where T : Base
    {
        this.attributes.AddRange(attributes);
        return this as T;
    }
}

public class Derived : Base
{
}

我想用fluent-api样式语法从派生类中调用Base.WithAttributes,并返回派生实例,如下例所示。

void Main()
{
    Derived d = new Derived();

    // CS0411 The type arguments for method 'UserQuery.Base.WithAttributes<T>(params string[])' cannot be inferred from the usage.
    d.WithAttributes("one", "two"); 

    // Works, but type arguments must be explicity specified. 
    d.WithAttributes<Derived>("one", "two");

    // Works without explicitly specifying, but no access to private members!
    d.WithAttributesEx("one", "two");
}

public static class Extensions
{
    public static T WithAttributesEx<T>(this T obj, params string[] attributes)
        where T : Base
    {
        // No access to private members, argh!
        // obj.attributes.AddRange(attributes);
        return obj as T;
    }
}
  1. 为什么编译器不能在第一个例子中推断出类型参数?
  2. 使用扩展方法调用时为什么会起作用?
  3. 有没有办法让它在基类上作为实例方法工作而不显式指定类型参数?
  4. 相关:https://stackoverflow.com/a/32123354/259808

1 个答案:

答案 0 :(得分:15)

  

为什么编译器不能在第一个例子中推断出类型参数?

类型推断使用方法参数来推断类型参数。在第一个示例中,没有可用于推断类型参数的方法参数。

  

使用扩展方法调用时为什么会起作用?

扩展方法实际上是一个静态的方法和对象,你正在扩展&#39;作为参数传递给扩展方法调用:

Extensions.WithAttributesEx<T>(d, "one", "two")

如上所述,类型推断使用方法参数来查找类型参数。这里类型参数可以从第一个方法参数的类型推断出来,即Derived

  

有没有办法让它在基础上作为实例方法工作   没有显式指定类型参数的类?

使基类通用并使用派生类(称为Curiously Recurring Template Pattern)对其进行参数化:

public class Base<T>
    where T : Base<T>
{
    private List<string> attributes = new List<string>();

    public T WithAttributes(params string[] attributes)            
    {
        this.attributes.AddRange(attributes);
        return this as T;
    }
}

public class Derived : Base<Derived>
{
}

用法:

Derived d = new Derived().WithAttributes("one", "two").WithAttributes("three");