C# 泛型类的方法不';看不见';新';子类的属性

C# 泛型类的方法不';看不见';新';子类的属性,c#,generics,inheritance,properties,C#,Generics,Inheritance,Properties,我有一个通用的树节点类ObservateRetreeNode,它的方法应该遍历树的所有节点并检查它们。我还有两门课: ElementTreeNode:ObservateTreeNode,以及 ElementTreeNodeVisual:ElementTreeNode 泛型类如下所示: public class ObservableTreeNode<K, V> { public K Key { get; set; } public V Value { get; set;

我有一个通用的树节点类
ObservateRetreeNode
,它的方法应该遍历树的所有节点并检查它们。我还有两门课:

ElementTreeNode:ObservateTreeNode
,以及
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;
    }
}
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));
        }
    }
}
}

我的问题是,当我尝试调用
elementTreeEndevisional.findNodeTree
方法时,该方法似乎看到了基类的
子类
属性,而基类没有项。 下面是我如何调用该方法的:

        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);
            }
        }
Func isExpandedFunc=delegate(elementtreeNode){return node.IsExpanded;};
foreach(分层节点设备中的元素树节点)
{
var expandedNodes=elementTreeNode.findNodeTree(节点,isExpandedFunc);
foreach(expandedNodes中的ElementTreeNode expandedNode)
{
expandedNodeId.Add(expandedNode.Key);
}
}
如果我在foreach循环中的
节点
变量上设置了一个watch,它将显示新的
子节点
属性,其中包含多个子节点。然而,
FindNodeInTree
方法中的
Debug.WriteLine(…)
表示有0个子级

作为紧急解决方案,我复制粘贴了
FindNodeInTree
方法,并将T参数更改为
,其中T:ElementTreeNodeVisual
。它是这样工作的,但最终不应该有任何复制粘贴的代码在那里


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

好吧,这是一个有点奇怪的方法,但应该可以工作。 首先,在基类中添加虚拟财产集合。例如:

public virtual ObservableCollection<ObservableTreeNode<K, V>> VirtualChildren { 
   get { return Children; }
}
公共虚拟可观察集合虚拟儿童{
获取{返回子项;}
}
在搜索方法中,将儿童更改为虚拟儿童

    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;
    }
    public override ObservableCollection<ObservableTreeNode<string, HierarchyElement>> VirtualChildren
    {
        get { return new ObservableCollection<ObservableTreeNode<string, HierarchyElement>>(Children); }
    }
公共静态IEnumerable FindNodeTree(
T rootNode,Func谓词,bool firstOnly=false
)式中T:可观测四节点
{
var resultNodes=新列表();
var nodeQueue=新队列();
nodeQueue.Enqueue(rootNode);
while(nodeQueue.Any())
{
T currentNode=nodeQueue.Dequeue();
WriteLine(“当前节点键:{0}”,currentNode.key);
if(谓词(当前节点))
{
Debug.WriteLine(“匹配!”);
resultNodes.Add(当前节点);
如果(仅限第一次)
{
Debug.WriteLine(“-FindInContext”);
返回结果节点;
}
}
WriteLine(“当前节点有{0}个子节点。”,currentNode.VirtualChildren.Count);
foreach(currentNode.VirtualChildren中的tn)
{
Debug.WriteLine(“排队子…”);
节点排队(n);
}
}
返回结果节点;
}
并覆盖元素树设计中的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;
    }
    public override ObservableCollection<ObservableTreeNode<string, HierarchyElement>> VirtualChildren
    {
        get { return new ObservableCollection<ObservableTreeNode<string, HierarchyElement>>(Children); }
    }
public override ObservableCollection虚拟儿童
{
获取{returnnewobserveCollection(Children);}
}

当然,每次在属性中返回新集合不是很好。因此,您可以使用虚拟方法替换此属性,也可以订阅ElementTreeEndevisional类中的CollectionChangedeventChildren属性,并实时向内部集合添加新元素,例如。

当通过对基类的引用访问基类方法或属性时,新修饰符不会隐藏该方法或属性。@AluanHaddad我知道这一点,但我假设当我显式调用泛型方法as时,T将是方法内部的ElementTreeEndevisional。如果这个假设是错误的,我们将如何解决这个问题?谢谢!与在子类中复制粘贴相同的方法相比,这仍然是一个非常优雅的解决方案。太糟糕了,WPF控制要求我们做这样的黑客。谢谢你们提出的有趣的问题。