引用我自己的类型的最佳方式

时间:2011-06-10 17:12:15

标签: c# generics

abstract class A<T> where T:A<T>
{
    public event Action<T> Event1;
}

class B : A<B>
{
    //has a field called Action<B> Event1;
}

有更优雅的方法吗?我希望基类中的东西(事件等)能够使用子类的类型。

5 个答案:

答案 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)

我认为你不需要指定T:A。

当你使用B类时,

T将是B:A

这也称为CRTP or Curiously recurring template pattern,是一种已知的习语。

答案 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();
        }
    }
}

通过这样做,我们可以播种一只邪恶的狗的种子,但是那只狗会在运行时被终止。