V. Pupkin
V. Pupkin

Reputation: 13

Troubles with accessing property in derivied class

I have an abstract class:

public abstract class Node
{
    protected readonly List<Node> Nodes = new List<Node>();
    public Node[] ChildNodes => Nodes.ToArray();
    ...
}

And derived from him:

public sealed class NodeArray<T> : Node where T: Node
{
    private readonly List<T> _array = new List<T>(); 
    private new List<Node> Nodes => _array.Cast<Node>().ToList();
    public new Node[] ChildNodes => _array.Cast<Node>().ToArray();
    ...
}

Node.Nodes list may contain NodeArray<Smth> through. But, when I'm trying to recursively enumerate nodes, and I'm getting one of type NodeArray, it returns empty ChildNodes value (of base class I guess). And when I debugged following code, Intellisense shows two identical properties with the same name and same type!

Screenshot

Loop code:

protected void LoadNode(Node node, XmlNode xmlNode)
    {
        foreach (XmlNode childNode in xmlNode.ChildNodes)
        {
            if (childNode.HasChildNodes)
            {
                var child = node.ChildNodes.First(p => p.Name == childNode.Name);  // <----- Stuck here
                if(child == null)
                    throw new Exception("Unknown child " + childNode.Name + " in Node " + node.Name);

                LoadNode(child, childNode);
            }
            else
            {
                node[childNode.Name] = childNode.Value;
            }
        }

        node.Load();
    }

Hope you help! Sorry for bed English :)

Upvotes: 0

Views: 50

Answers (1)

Douglas
Douglas

Reputation: 54877

Your issue might be that you're using member hiding (with the new keyword) rather than overriding. With member hiding, the base class and the derived class contain separate definitions of the property, despite having the same name. Thus, if you create a NodeArray<T> instance, populate its _array collection, and then pass it as a Node reference, then ChildNodes property would still be returning the empty collection of the Node.Nodes base property, rather than the NodeArray<T>._array field like you'd expect.

To resolve this issue, switch to using virtual and overridden members, as shown below:

public abstract class Node
{
    protected virtual List<Node> Nodes { get; } = new List<Node>();
    public virtual Node[] ChildNodes => Nodes.ToArray();
    ...
}

public sealed class NodeArray<T> : Node where T: Node
{
    private readonly List<T> _array = new List<T>(); 
    protected override List<Node> Nodes => _array.Cast<Node>().ToList();
    public override Node[] ChildNodes => _array.Cast<Node>().ToArray();
    ...
}

Upvotes: 1

Related Questions