泛型类的方法不会看到子类的“新”属性

时间:2013-11-18 09:43:49

标签: c# generics inheritance properties

我有一个通用树节点类ObservableTreeNode<K,V>,其方法应该遍历树的所有节点并检查它们。我还有两节课:

ElementTreeNode : ObservableTreeNode<string, HierarchyElement>,和  ElementTreeNodeVisual : ElementTreeNode

泛型类看起来像这样:

public class ObservableTreeNode<K, V>
{
    public K Key { get; set; }
    public V Value { get; set; }

    public ObservableCollection<ObservableTreeNode<K, V>> Children { get; set; }

    public ObservableTreeNode()
    {
        this.Children = new ObservableCollection<ObservableTreeNode<K, V>>();
    }

    public static IEnumerable<T> FindNodeInTree<T>(
            T rootNode, Func<T, bool> predicate, bool firstOnly = false
        ) where T : ObservableTreeNode<K, V>
    {
        var resultNodes = new List<T>();
        var nodeQueue = new Queue<T>();
        nodeQueue.Enqueue(rootNode);
        while (nodeQueue.Any())
        {
            T currentNode = nodeQueue.Dequeue();
            Debug.WriteLine("Current node key: {0}", currentNode.Key);
            if (predicate(currentNode))
            {
                Debug.WriteLine("Match!");
                resultNodes.Add(currentNode);
                if (firstOnly)
                {
                    Debug.WriteLine("-FindInContext");
                    return resultNodes;
                }
            }
            Debug.WriteLine("The current node has {0} children.", currentNode.Children.Count);
            foreach (T n in currentNode.Children)
            {
                Debug.WriteLine("Enqueue child...");
                nodeQueue.Enqueue(n);
            }
        }
        return resultNodes;
    }
}

在我的ElementTreeNodeVisual课程中,我必须使用新版本隐藏Children属性,否则我的WPF应用程序中的第三方(Infragistics'XamDataTree)控件将不会枚举子节点。所以我的ElementTreeNodeVisual类看起来像这样:

public class ElementTreeNodeVisual : ElementTreeNode
{
    public bool IsExpanded { get; set; }
    public bool IsSelected { get; set; }

    public new ObservableCollection<ElementTreeNodeVisual> Children 
    {
        get;
        set;
    }

    public ElementTreeNodeVisual(ElementTreeNode elementTreeNode)
    {
        this.Children = new ObservableCollection<ElementTreeNodeVisual>();
        this.Element = elementTreeNode.Element;
        this.Parent = elementTreeNode.Parent;
        foreach (ElementTreeNode child in elementTreeNode.Children)
        {
            this.Children.Add(new ElementTreeNodeVisual(child));
        }
    }
}

}

我的问题是,当我尝试调用ElementTreeNodeVisual.FindNodeInTree方法时,该方法似乎看到了基类的Children属性 - 它没有项目。 这就是我调用方法的方法:

        Func<ElementTreeNodeVisual, bool> isExpandedFunc = delegate(ElementTreeNodeVisual node) { return node.IsExpanded; };
        foreach (ElementTreeNodeVisual node in _hierarchyNodeVisuals)
        {
            var expandedNodes = ElementTreeNodeVisual.FindNodeInTree<ElementTreeNodeVisual>(node, isExpandedFunc);
            foreach (ElementTreeNode expandedNode in expandedNodes)
            {
                expandedNodeIds.Add(expandedNode.Key);
            }
        }

如果我在foreach循环内的node变量上设置监视,它会显示具有多个子节点的新Children属性。然而,Debug.WriteLine(...)方法中的FindNodeInTree表示有0个孩子。

作为紧急解决方案,我已复制粘贴FindNodeInTree方法并将T参数更改为where T : ElementTreeNodeVisual。它的工作方式如下,但最终不应该有任何复制粘贴的代码...

我应该更改(在泛型类或子类中)以使FindNodeInTree方法在子类上调用它时看到新属性?

1 个答案:

答案 0 :(得分:1)

嗯,这是一个有点奇怪的方法,但它应该有效。 首先,在基类中添加虚拟属性集合。例如:

public virtual ObservableCollection<ObservableTreeNode<K, V>> VirtualChildren { 
   get { return Children; }
}

在您的搜索方法中,将儿童更改为 VirtualChildren

    public static IEnumerable<T> FindNodeInTree<T>(
            T rootNode, Func<T, bool> predicate, bool firstOnly = false
        ) where T : ObservableTreeNode<K, V>
    {
        var resultNodes = new List<T>();
        var nodeQueue = new Queue<T>();
        nodeQueue.Enqueue(rootNode);
        while (nodeQueue.Any())
        {
            T currentNode = nodeQueue.Dequeue();
            Debug.WriteLine("Current node key: {0}", currentNode.Key);
            if (predicate(currentNode))
            {
                Debug.WriteLine("Match!");
                resultNodes.Add(currentNode);
                if (firstOnly)
                {
                    Debug.WriteLine("-FindInContext");
                    return resultNodes;
                }
            }
            Debug.WriteLine("The current node has {0} children.", currentNode.VirtualChildren.Count);
            foreach (T n in currentNode.VirtualChildren)
            {
                Debug.WriteLine("Enqueue child...");
                nodeQueue.Enqueue(n);
            }
        }
        return resultNodes;
    }

并覆盖 ElementTreeNodeVisual 中的 VirtualChildren 属性:

    public override ObservableCollection<ObservableTreeNode<string, HierarchyElement>> VirtualChildren
    {
        get { return new ObservableCollection<ObservableTreeNode<string, HierarchyElement>>(Children); }
    }

当然,每次归还新物品都不是很好。因此,您可以通过虚拟方法替换此属性,或者订阅 ElementTreeNodeVisual 类中的 CollectionChanged 事件子级属性,并将新元素添加到内部集合中例如,实时。