abstract class A<T> where T:A<T>
{
public event Action<T> Event1;
}
class B : A<B>
{
//has a field called Action<B> Event1;
}
有更优雅的方法吗?我希望基类中的东西(事件等)能够使用子类的类型。
答案 0 :(得分:5)
您使用的模式实际上并未实现您想要的约束。假设您想要模仿“动物只能与自己的某种东西友好”:
abstract class Animal<T> where T : Animal<T>
{
public abstract void GetFriendly(T t);
}
class Cat : Animal<Cat>
{
public override void GetFriendly(Cat cat) {}
}
我们是否已成功实施所需的约束?否。
class EvilDog : Animal<Cat>
{
public override void GetFriendly(Cat cat) {}
}
现在一只邪恶的狗可以与任何猫友好,并且与其他邪恶的狗不友好。
在C#类型系统中无法实现所需的类型约束。如果您需要类型系统强制执行的这种约束,请尝试使用Haskell。
有关详细信息,请参阅我关于此主题的文章:
http://blogs.msdn.com/b/ericlippert/archive/2011/02/03/curiouser-and-curiouser.aspx
答案 1 :(得分:2)
你的工作得很好。事实上,它与其他.NET接口和类型非常相似,您希望接口实现者使用您的类型,例如:
public class MyClass : IEqualityComparer<MyClass>
{
// From the interface IEqualityComparer
public bool Equals(MyClass other) { ... }
...
}
答案 2 :(得分:0)
答案 3 :(得分:0)
由于A是抽象的,你可以向A添加抽象方法并从A和B调用它们,这将被强制实现该方法,将是调用者:
abstract class A<T> where T:A
{
public event Action<T> Event1;
public abstract void Method();
public A(){Method();}
}
class B : A<B>
{
//has a field called Action<B> Event1;
public void Method(){ //stuff }
}
在B的实例化时,基类构造函数将调用仅在B中实现的Method(),强制调用B的实例。
这允许A调用子类特定的方法,而不需要A具有Children的特定知识。缺点是所有孩子都必须实施Method或将其重新抽象给自己的孩子。
答案 4 :(得分:0)
我最近的question被标记为与此人的副本。我完全同意这一点。所以我来这里看看答案,并阅读了Eric关于该问题的帖子(确实很有趣)。您不能使用类型系统在编译时强制执行此操作,但是可以在运行时执行此操作。我实现此方法的方式是:
abstract class FooBase<T>
{
protected FooBase()
{
if (typeof(T) != GetType())
{
throw new InvalidOperationException();
}
}
}
通过这样做,我们可以播种一只邪恶的狗的种子,但是那只狗会在运行时被终止。