我有一个类似于这个的类层次结构:
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;
}
}
答案 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");