【问题标题】:Generics and Inheritance with Collections集合的泛型和继承
【发布时间】:2011-03-24 04:57:05
【问题描述】:

我已经阅读了许多其他相关的问题,但仍然无法完全弄清楚如何做我们需要做的事情。使用泛型不是必须的,但似乎是我们可能获得所需的唯一方法。我们在 .net 3.5 中,所以我们不能使用我认为相关的新的 .net 4.0 东西。假设我们有一个具有一些属性和方法的基类 Parent。我们还有一个 ParentCollection,它目前实现了 IEnumerable。我们还为这个类添加了额外的属性和方法。

我们现在需要从 Parent 继承来创建 ChildA。但是,我们还需要从 ParentCollection 继承来创建 ChildACollection。然后,我们将 ChildA 的对等类作为 ChildB 和 ChildBCollection。

ChildACollection 和 ChildBCollection 及其项是唯一实际实例化的东西。 Parent 的东西是抽象的。

ParentCollection 和 Parent 上有一些方法可以返回满足条件的项目子集,也可能被操纵。

问题是由于这些方法正在处理集合中的项目,我们希望返回的集合是后代的类型。例如通过 ChildACollection 的实例调用在 ParentCollection 中定义的方法 SomeMethod(),因此子集返回的类型是 List 而不是 List。

有没有办法实现这种功能?

我们正在尝试做的示例伪代码

public class Parent
{
    public string PropA { get; set; }
    public int PropB { get; set; }

    public void DoSomething() { }
}

public class ParentCollection : IEnumerable<Parent>
{
    protected List<Parent> _list = new List<Parent>();

    public IEnumerator<Parent> GetEnumerator()
    {
        return _list.GetEnumerator();
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }

    public List<Parent> SomeSelectMethod()
    {
        List<Parent> list = new List<Parent>();

        // DO LOGIC HERE TO DETERMINE WHAT ITEMS WILL BE IN LIST

        return list;
    }

}

public class ChildA : Parent
{
    public double PropC { get; set; }

    public void DoSomethingElse() { }
}

public class ChildACollection : ParentCollection
{
    public void SomeChildMethod() { }
}

public class MyTestClass
{
    public void Main()
    {
        ChildACollection myCollection = new ChildACollection();

        //HERE IS THE PROBLEM
        List<ChildA> childList = myCollection.SomeSelectMethod();
    }

}

基本上我想利用继承,但不让 ChildACollection 的用户必须不断地将列表中返回的对象引用转换为 ChildA 对象。我的意思是内部列表将具有实际的 ChildA 对象而不是 Parent 对象,但由于该方法位于 ParentCollection 类中,它只知道它是 Parent 或后代类的对象。希望这是有道理的。

帮助?

跟进问题: 我需要将此层次结构更深一层(孙子)并在 Parent 上添加一个 Add 方法,该方法将创建并将适当的对象类型添加到列表中,即如果在 ChildCollection 引用上调用 Add ,它应该创建并添加一种 Child 并返回对列表中新创建的对象的引用。可能吗?

【问题讨论】:

  • 受保护列表 _list = new List();你知道你已经继承了 IEnumerable,这实际上是一个列表,所以你不需要 _list 元素成为类的一部分。

标签: c# generics


【解决方案1】:

您可以使用泛型类型参数约束:

    class ParentCollection<T> where T : Parent {
        public List<T> SomeSelectMethod()
        {
            List<T> list = new List<T>();

            // can treat T as Parent here

            return list;
        }
    }

    class ChildACollection : ParentCollection<ChildA> {
    }

    class ChildBCollection : ParentCollection<ChildB> {
    }

您也可以考虑从 System.Collections.ObjectModel.Collection 继承,这样您就不必实现 IEnumerable。

后续跟进:

我的理解是,您希望在父集合上有一个无参数方法 Add(),该方法创建 T 类型的实例,将其添加到集合中并返回它。一种方法是在 T 上添加一个额外的约束:

class ParentCollection<T> where T : new(),Parent {
       public T Add() {
        var item = new T();
         Add(item);
         return item;
       }
    }

【讨论】:

    【解决方案2】:

    那么,基本上您希望该人能够调用 SomeSelectMethod 并获取 List、List 或 List?

    您可以使用通用参数和一些 LINQ 来做到这一点。

    public List<T> SomeSelectMethod<T>()
       where T : Parent
    {
         return this.Where(x => x.MatchesSomeExpression && x is T).Cast<T>().ToList();
    }
    

    【讨论】:

      【解决方案3】:

      您可以将 ParentCollection 设为泛型类。 试试:

      public class ParentCollection&lt;T&gt; : IEnumerable&lt;T&gt; where T:Parent

      并用 .

      替换该类中的每个

      那你就可以class ChildACollection : ParentCollection&lt;ChildA&gt;

      【讨论】:

        【解决方案4】:

        这里有一个解决方案。

        public class ParentCollection<T> : IEnumerable<T> where T : Parent
        {
            protected List<T> _list = new List<T>();
        
            public IEnumerator<T> GetEnumerator()
            {
                return _list.GetEnumerator();
            }
        
            System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
            {
                return GetEnumerator();
            }
        
            public virtual List<T> SomeSelectMethod()
            {
                List<T> list = new List<T>();
        
                // DO LOGIC HERE TO DETERMINE WHAT ITEMS WILL BE IN LIST
                return list;
            }
        }
        
        public class ChildACollection : ParentCollection<ChildA>
        {
            public void SomeChildMethod()
            {
            }
            //You have the method inherited.
        }
        

        【讨论】:

        • 这就是我要去的地方。我添加了一个关于添加第三级继承的后续问题。
        猜你喜欢
        • 1970-01-01
        • 2010-10-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-25
        • 1970-01-01
        相关资源
        最近更新 更多