奇怪的通用继承模式

时间:2015-12-10 22:41:37

标签: c# generics inheritance

在一些研究中,我使用我以前从未见过的泛型来尝试继承模式。

http://thwadi.blogspot.ca/2013/07/using-protobuff-net-with-inheritance.html

public abstract class BaseClass<TClass> where TClass : BaseClass<TClass>
{
    //...
}
public class DerivedClass : BaseClass<DerivedClass>
{
    //...
}

用法:

static void Main(string[] args)
{
    DerivedClass derivedReference = new DerivedClass();

    //this looks odd...
    BaseClass<DerivedClass> baseReference = derivedReference;

    //this doesn't work
    //BaseClass baseClass = derivedReference;

}

我很惊讶这甚至有效,我必须自己测试一下。我仍然无法理解你为什么要这样做。

我唯一能想到的是阻止不同的派生类作为基类存储在集合中。这可能是原因,我想我只是对应用程序感到好奇。

2 个答案:

答案 0 :(得分:4)

它被称为Curiously recurring template pattern,它通常用于允许类中的方法将派生类的类型用作传入或返回的参数。

例如,这是实现的Clone方法,因此只有每个层都需要在方法向下链时向方法添加它自己的属性。

public abstract class BaseClass<TClass> where TClass : BaseClass<TClass>, new()
{
    public int Foo {get;set;}

    public virtual TClass Clone()
    {
        var clone = new TClass();
        clone.Foo = this.Foo;
        return clone;
    }
}
public class DerivedClass : BaseClass<DerivedClass>
{
    public int Bar {get;set;}

    public override DerivedClass Clone()
    {
        var clone = base.Clone();
        clone.Bar = this.Bar;
        return clone;
    }
}

用法:

static void Main(string[] args)
{
    DerivedClass derivedReference = new DerivedClass();

    DerivedClass clone = derivedReference.Clone();    
}

答案 1 :(得分:3)

作为使用示例,假设您要在基类型和派生类型上实现一些可链接的构建器方法,如下所示:

var d = new DerivedClass();
d.SetPropertyA("some value").SetPropertyB(1);

虽然SetPropertyA属于基类,SetPropertyB属于派生类。

通过实现如下所示的类,在链接方法时,在调用SetPropertyA之后,因为返回值的类型为DerivedClass,您可以调用SetPropertyB

public abstract class BaseClass<TClass> where TClass : BaseClass<TClass>
{
    public string A {get ; set; }
    public TClass SetPropertyA(string value)
    {
        this.A=value;
        return this as TClass;
    }
}

public class DerivedClass : BaseClass<DerivedClass>
{
    public int B {get ; set; }
    public DerivedClass SetPropertyB(int value)
    {
        this.B=value;
        return this;
    }
}

然后,如果你有一些其他的派生类,每个派生类都可以使用基础SetPropertyA知道返回值是它自己的类型。