简体   繁体   中英

C# Derived classes with properties of different derived types

Is there a way in C# to accomplish something like the following? prop in each of the containers should be the same property, ie referencing prop from inside a childContainer should access the same object as code inside baseContainer.

I want to be able to reference the property in functions within baseContainer while other code references the properties of the childContainers without needing to cast the property to the more specific class. I also need to be able to use prop when I only have a reference to an object of type baseContainer, regardless of what the actual type of the object is, ie I don't care if it's actually a derived type.

I'm open to refactoring to use a different pattern if someone can suggest one.

    public class baseContainer
    {
        public basePropType prop {get; set;}
    }

    public class childContainer1 : baseContainer
    {
        public childProp1 prop {get; set;}
    }

    public class childContainer2 : baseContainer
    {
        public childProp2 prop {get; set;}
    }

    public class basePropType
    {
    }

    public class childProp1 : basePropType
    {
    }

    public class childProp2 : basePropType
    {
    }

    // elsewhere in another class
    baseContainer container = GetContainer(); // Don't know which child class this object actually is
    basePropType propVal = container.prop;

Hope this makes sense.

Context: The GetContainer() in the code sample was just an attempt to illustrate that I have a baseContainer ref that could reference an object of one of the derived classes. A simplification to try and make this readable without posting dozens of classes and masses of IP that my employer wouldn't really appreciate me posting :-)

The real structure, involves a class creating an object of a either childContainer1 or childContainer2 (the real app has many more derived classes and may eventually have more classes derived from these, ie multiple levels of inheritance), and doing some processing, which relies on it being this specific type but then passes it onto multiple another services that don't care which specific classes are being used, they just handle the baseContainer.

Not sure if this makes a difference to the solution but I've been asked for extra context.

Sure, you can achieve this with generics!

public class BasePropType { }
public class ChildProp1 : BasePropType { }
public class ChildProp2 : BasePropType { }

public abstract class BaseContainer<T> where T : BasePropType
{
    public T Prop { get; set; }
}

public class ChildContainer1 : BaseContainer<ChildProp1> { }
public class ChildContainer2 : BaseContainer<ChildProp2> { }

This can also be solved without generics, and using interfaces.

public interface IBaseType { }
public class ChildProp1 : IBaseType { }
public class ChildProp2 : IBaseType { }

public abstract class BaseContainer
{
    protected BaseContainer(IBaseType type)
    {
        Prop = type;
    }

    public IBaseType Prop { get; private set; }
}

public class ChildContainer1 : BaseContainer
{
    public ChildContainer1()
     : base(new ChildProp1())
    {

    }
}

public class ChildContainer2 : BaseContainer
{
    public ChildContainer2()
     : base(new ChildProp2())
    {

    }
}

You can also use shadowing and casting to achieve this:

public class baseContainer
{
    public basePropType prop { get; set; }
}

public class childContainer1 : baseContainer
{
    public new childProp1 prop 
    {
        get => (childProp1)base.prop;
        set => base.prop = value;
    }
}

This has the overhead of a cast and the possibility of an invalid cast if for any reason the baseContainer sets prop to a value that is not of type childProp1 (which in your case is not supposed to happen as far as I understand the prerequisite).

Still the best way in my opinion is to use a new property to avoid the name-clash:

public class baseContainer
{
    public virtual basePropType prop { get; set; }
}

public class childContainer1 : baseContainer
{
    public childProp1 childProp { get; set; }

    public override basePropType prop 
    {
        get => childProp;
        set => (childProp1)childProp
    }
}

This avoids confusion about the different types of the (seemingly) same property and adds more type safety in case a wrong class could be assigned to the property.

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