简体   繁体   中英

Derived classes with derived properties

I have 2 classes that are both derived from a base class X. The base class contains a property of a class T. Both subclasses of X should contain a property that's derived from T.

What I would like to achieve is to declare the a property of T in the base class X and have it used in several methods, while using the same property of T in the derived classes of X but have it recognized as a derived class from T, so that I won't have to cast it every time I want to use it.

One of my solutions would be just remove the property from the base class and copy the methods for each derived class of X, but that would defeat the purpose of using inheritance.

Is anything like that achievable?

internal class TestObject
{
    public string ID;
    public XObject obj;
    //....
} 

internal class TestDocument : TestObject
{
    public XDocument obj; //<--- want to be able to call obj in my methods 
    //as if it were an XDocument type but relate to the obj property in the base class
    //....
} 

internal class XObject
{
    //....
}

internal class XDocument : XObject
{
    //....
}

Generics should work for you:

class Base<T> where T: MyType
{
    T MyProperty { get; set; }
    public void DoSomething()
    {
        // do something with MyProperty
    }
}

with MyType being the base-class of the property within Base .

Then in your derived class you can define the generic constraint, eg

class Derived : Base<DerivedType>
{
}

Now an instance of Derived has the property MyProperty of type DerivedType instead of MyType .

So in your case TestObject should be similar to this:

internal class TestObject<T> where T: XObject 
{
    public string ID;
    public T obj;
    //....
}    
internal class TestDocument : TestObject<XDocument>
{
    // obj is here of type XDocument
} 

Make the type of the property a generic parameter of your base class:

class PropertyTypeBase { }
class PropertyTypeA : PropertyTypeBase { }

class Base<T> where T : PropertyTypeBase
{
    public T Property { get; }
}

class Foo :  Base<PropertyTypeA>
{
    public Foo()
    {
        PropertyTypeBase x = Property;
        PropertyTypeA a = Property;
    }
}

The simplest way would be to make the base class generic, and constrain the generic parameter to be derived form a certain class:

class BaseProp { }
class DerivedPropA: BaseProp { }
class DerivedPropB : BaseProp { }

abstract class X<T>
    where T: BaseProp
{
    public T Value { get; set; }

    public abstract void With(T value);
}
class A : X<DerivedPropA>
{
    public override void With(DerivedPropA value)
    {
        this.Value = value;
    }
}

class B : X<DerivedPropB>
{
    public override void With(DerivedPropB value)
    {
        this.Value = value;
    }
}

This is possible by using generics.

First, let me explain the example classes. Let's say these are your properties:

public class BaseHead {}
public class OrganicHead : BaseHead {}
public class CyborgHead : BaseHead {}

And you now want to implement these heads on your person classes:

public class BaseCreature {}
public class OrganicCreature : BaseCreature {}
public class CyborgCreature : BaseCreature {}

The solution:

public class BaseCreature<THead> where THead : BaseHead 
{
    public THead Head { get; set; }

    public BaseCreature(THead head)
    {
        this.Head = head;
    }       
}
  • We make the BaseCreature generic
  • We limit the THead type to only allow types that either are BaseHead or are derived from BaseHead

However, we also want to ensure that the right creature (organic/cyborg) only uses the correct head (organic/cyborg). This can be done by deriving from a BaseCreature with a specific generic type:

public class OrganicCreature : BaseCreature<OrganicHead> 
{
    public OrganicCreature(OrganicHead head) : base(head) 
    {

    }
}

CyborgCreature is analogous.


Suppose you wanted to make it possible that every creature can use every type of head. If that's what you want, then you need to keep the generic parameter generic:

public class OrganicCreature<THead> : BaseCreature<THead>  where THead : BaseHead 
{
    public OrganicCreature(THead head) : base(head)
    {

    }
}

CyborgCreature is analogous.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM