Changing the Type of a inherited property (to a in

2020-03-15 06:30发布

问题:

using C# I have a class which contains among other meta information the root node of a directed graph. Let's call this the Container-Class. This container can appear in two different modes, Editor-Mode and Configurator-Mode. Depending on the mode, the root-node is of a different type NodeEdit or NodeConfig, both inheriting from the same subclass.

public abstract class NodeBase
{
  string Name { get; set; }
  ...
}

public class NodeEdit : NodeBase ...
public class NodeConfig : NodeBase ...

For the container, I also create a base class and inherit from it:

public abstract class ContainerBase
{
  NodeBase Root { get; set; }
  ...
}

When creating the classes for Editor- and Configuratorcontainer by inheriting from ContainerBase, I want to become the type of the Root - property the specific (inherited from NodeBase) type like:

public class ContainerEditor : ContainerBase
{
  NodeEditor Root { get; set; }
  ...
}

But I cannot change the type of a property defined in ContainerBase. Is there a way to solve this problem? I can use the BaseNode-type, and add an element of NodeEditor like

ContainerEditorInstance.Root = new NodeEditor();

because the type NodeEditor is inherited from type BaseEditor, but in the Container-Editor class, I want to explicitly only allow the type of the Root-property to be NodeEditor. I could check this in the setter and reject all nodes but those of type NodeEditor, but I'd like to have the property be of the specific type, so I can detect wrong assignments at compile-time.

Thanks in advance,
Frank

回答1:

You can redeclare it:

public class ContainerEditor : ContainerBase
{
  public NodeEditor Root {
    get { return (NodeEditor)base.Root; }
    set { base.Root = value; }
  }
  ...
}


回答2:

Use generics:

public abstract class ContainerBase<T> where T:NodeBase
{
  T Root { get; set; }
  ...
}

public class ContainerEditor : ContainerBase<NodeEditor>
{      
  ...
}


回答3:

You can make the container base generic:

public abstract class ContainerBase<TRoot> where TRoot : NodeBase
{
  TRoot Root { get; set; }
  ...
}

In the derived class you specify the type:

public class ContainerEditor : ContainerBase<NodeEditor>
{
  ...
}


回答4:

I suppose a good solution here will be Generics. So you'd write something like this:

public class ContainerEditor<T>:ContainerBase
{
    T Root {get;set;}
}