有点理论问题。很长一段时间,如果你不喜欢理论,可以随意跳过。
想象一下,你有两个类,一个继承自另一个。基类是通用的,并且有一个方法,在闭合类型中必须返回此闭合类型的某个实例。
像这样(注意文字中的 ??? ):
public class Adapter<T>
{
public virtual ??? DoSomething()
{
...
}
}
public class AdaptedString : Adapter<String>
{
public override AdaptedString DoSomething()
{
...
}
}
我不能这样做,因为无法引用将从泛型类型派生的闭合类型。 (对不起破解语言,只是不知道如何表达它。)没有设置关键字代替???
来指定此方法将返回将从此泛型类型派生的类型的实例。
相反,我可以使用显式将类型名称传递给通用基础的变通方法。但它看起来多余。
public class Adapter<TThis,T>
{
public virtual TThis DoSomething()
{
...
}
}
public class AdaptedString : Adapter<AdaptedString,String>
{
public override AdaptedString DoSomething()
{
...
}
}
如果在基类中我需要访问TThis
实例的成员,我必须添加一个约束。这一次看起来很难看 - 请注意约束:
public class Adapter<TThis,T>
where TThis : Adapter<TThis, T>
{
protected int _field;
...
public bool Compare( TThis obj )
{
return _field == obj._field;
}
}
public class AdaptedString : Adapter<AdaptedString,String>
{
...
}
是的,它一切正常,但如果我只是在第一个代码片段中使用一些关键字而不是???
,它看起来会更好。像“ thistype ”之类的东西。
您认为它如何运作?它有用吗?或者这可能只是愚蠢的?
答案 0 :(得分:11)
没有任何东西可以让这种模式变得更容易,事实上这种模式无论如何都不是防弹 - 因为你可以拥有:
class TypeA : Adapter<TypeA, string>
class TypeB : Adapter<TypeA, string> // Bug!
这里的第二行完全合法 - TypeA
是TThis
类型参数的有效类型参数,即使它不是我们想要的。基本上,类型系统不允许我们表达“T必须是这种类型”的概念。
Foo foo = new Foo.Builder { Name="Jon" }.Build();
即使在Foo.Build()
中指定了Foo
方法,如果Build
未被强类型返回IBuilder<...>
,也无效。
如果你很容易可以因为它变得如此复杂 - 值得避免这种情况 - 但我确实认为这是一个有用的模式。
答案 1 :(得分:5)
在这种情况下,您通常只想引用基类:
public class Adapter<T> {
public virtual Adapter<T> DoSomething();
尝试执行您正在执行的操作违反了Liskov substitution principal。
答案 2 :(得分:-1)
如果派生类中的继承方法需要返回派生类型而不是基类型(称为covariant return type),则C#中已经支持此功能。
答案 3 :(得分:-1)
我也很难找到一个有争议的用例(虽然这是一个有趣的想法)。
您是否试图转变如何约束您可以使用的通用类型?听起来你想在不知道实际类型的情况下假设一些基本功能;这就是接口的用途。 where子句对于这些问题非常方便。
class Dictionary<K, V>
where K : IComparable, IEnumerable
where V : IMyInterface
{
public void Add(K key, V val)
{
}
}
上面的示例约束K(密钥),因此它必须具有可比性和可枚举性,并且V必须通过您自己的界面实现您想要的任何客户功能。