Odd Generic Inheritance pattern

元气小坏坏 提交于 2020-02-03 17:15:07

问题


During some research, I ran into an inheritance pattern using generics I have not seen before.

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>
{
    //...
}

Usage:

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

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

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

}

I was surprised that this even worked, I had to test it myself. I still can't understand why you would want to do this.

The only thing I could come up with, is preventing different derived classes from being stored in a collection together as their base class. This may be the reason, I guess I'm just curious to the application.


回答1:


It is called the Curiously recurring template pattern it is often used to allow methods in the class to use the type of the derived class as a passed in or returned parameter.

For example, this is Clone method implemented so that only each layer needs to add it's own properties to the method as it goes down the chain.

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;
    }
}

Usage:

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

    DerivedClass clone = derivedReference.Clone();    
}



回答2:


As an example of usage, suppose you want to implement some chainable builder methods on the base type and derived type like this:

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

While SetPropertyA belongs to base class and SetPropertyB belongs to derived class.

By implementing classes like below, when chaining methods, after calling SetPropertyA because the return value is of type DerivedClass you can call 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;
    }
}

Then if you have some other derived classes, each of them can use the base SetPropertyA knowing the return value is of type of itself.



来源:https://stackoverflow.com/questions/34213055/odd-generic-inheritance-pattern

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!