C# 参考我自己类型的最佳方式 抽象类A,其中T:A { 公共事件行动事件1; } B类:A { //有一个名为Action Event1的字段; }

C# 参考我自己类型的最佳方式 抽象类A,其中T:A { 公共事件行动事件1; } B类:A { //有一个名为Action Event1的字段; },c#,generics,C#,Generics,有没有更优雅的方法?我希望基类中的东西(事件等)能够使用子类的类型 我认为您不需要指定t:A的位置 当你使用B类:A时,T将是B 这也被称为并且是一个众所周知的习惯用法。你所拥有的非常有效。事实上,它与您希望接口实现者使用您的类型的其他.NET接口和类型非常相似,例如: abstract class A<T> where T:A<T> { public event Action<T> Event1; } class B : A<B> {

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

我认为您不需要指定t:A的位置

当你使用B类:A时,T将是B


这也被称为并且是一个众所周知的习惯用法。

你所拥有的非常有效。事实上,它与您希望接口实现者使用您的类型的其他.NET接口和类型非常相似,例如:

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

class B : A<B>
{
    //has a field called Action<B> Event1;
}
公共类MyClass:IEqualityComparer
{
//从接口IEqualityComparer
公共布尔等于(MyClass其他){…}
...
}

由于A是抽象的,您可以将抽象方法添加到A并从A调用它们,而B将被迫实现该方法,它将是调用程序:

public class MyClass : IEqualityComparer<MyClass>
{
    // From the interface IEqualityComparer
    public bool Equals(MyClass other) { ... }

    ...
}
抽象类A,其中T:A
{
公共事件行动事件1;
公开摘要无效方法();
公共A(){Method();}
}
B类:A
{
//有一个名为Action Event1的字段;
public void方法(){//stuff}
}
在实例化B时,基类构造函数将调用仅在B中实现的方法(),从而强制调用B的实例


这允许调用特定于子类的方法,而不需要具有子类的特定知识。缺点是,所有子级都必须实现方法或将其重新抽象为自己的子级。

您使用的模式实际上并没有实现您想要的约束。假设您想模拟“动物只能对其同类友好”:

抽象类动物,其中T:Animal
{
公开摘要(T);
}
类别猫:动物
{
公共覆盖无效GetFriendly(Cat){}
}
我们是否成功地实现了所需的约束?没有

abstract class Animal<T> where T : Animal<T>
{
    public abstract void GetFriendly(T t);
}

class Cat : Animal<Cat>
{
    public override void GetFriendly(Cat cat) {}
}
狗类:动物
{
公共覆盖无效GetFriendly(Cat){}
}
现在,一只邪恶的狗可以与任何猫友好相处,而不能与其他邪恶的狗友好相处

您想要的类型约束在C#type系统中是不可能的。如果需要类型系统强制执行此类约束,请尝试Haskell

有关更多详细信息,请参阅我的文章:

我最近的一次被标记为这一次的重复。我完全同意那件事。所以我来这里看看答案,并阅读Eric关于这方面的帖子(确实非常有趣)。您不能在编译时对类型系统强制执行此操作,但可以在运行时执行此操作。我实现这一点的方式是:

class EvilDog : Animal<Cat>
{
    public override void GetFriendly(Cat cat) {}
}
抽象类FooBase
{
受保护食物库()
{
if(typeof(T)!=GetType())
{
抛出新的InvalidOperationException();
}
}
}

通过这样做,我们可以播下一只邪恶狗的种子,但这只狗将在运行时被中止。

小心,基类不应该直接知道它的子类,它会成为一笔讨厌的技术债务。在这种情况下,因为它是一个泛型,所以不太糟糕,但只是一般性的。你不是说
其中t:a
?Eric Lippert已经写过:我认为您指出了一个重要的限制,但根据实际需求,这可能是一个严重的问题,也可能不是。例如,如果这只是在一个人自己的代码库中使用,那么如果模式被正确实现,从风格上看可能是显而易见的。我完全不同意。有一个简单的解决方案,你认为存在的问题与此技术。
class EvilDog : Animal<Cat>
{
    public override void GetFriendly(Cat cat) {}
}
abstract class FooBase<T>
{
    protected FooBase()
    {
        if (typeof(T) != GetType())
        {
            throw new InvalidOperationException();
        }
    }
}