【问题标题】:Generic Method for List of Generic Classes泛型类列表的泛型方法
【发布时间】:2017-08-24 09:50:39
【问题描述】:

我有问题。 例如,考虑这 4 个类。

public abstract ParentContainer<T> where T: Parentfoo
{
    public List<T> fooList; 
}

//Let there be many different ChildContainers with different types.
public class ChildContainer : ParentContainer<ChildFoo>
{
}

public abstract class ParentFoo
{
    public string name; 
}

public class ChildFoo : ParentFoo
{
}

我如何编写一个接受任意 ChildContainer 列表作为参数的方法, 哪些对他们的 fooLists 进行操作? 有没有可能?

补充说明,ParentContainer有很多不同的children, 每个都有一个 foo 的不同子项的列表。

public class ChildContainerB : ParentContainer<ChildFooB>{}
public class ChildContainerC : ParentCOntainer<ChildFooC>{}
...

public class ChildFooB : ParentFoo;
public class ChildFooC : ParentFoo;

那我需要一个类似这样的方法

//X means it can be any arbitrary ChildContainer
public void method(List<ChilContainerX> list) 
{
    foreach(ChildContainerX x in list)
    {
        print(x.fooList.Last().name);
    }
}

【问题讨论】:

  • 所有ChildContainer 实例都会有一个ChildFoo 列表,所以是的,这是可能的,但我怀疑这不是你想要的。你能解释一下吗?
  • 您至少可以编译您发布的示例代码吗?什么是foo,你的意思是ParentFoo
  • 另外,当你说任意ChildContainers的列表时,你真的是说任何继承自ParentContainer的对象的列表 ?
  • @DavidG 是的,我就是这个意思。
  • @GiulioCaccin 是的,对不起。我已经更正了我的示例代码!感谢您的提示!

标签: c# list class generics methods


【解决方案1】:

所以您的要求是不可能的,因为您需要List&lt;&gt; 的具体类型。不过有几个解决方法。

  1. 使用List&lt;object&gt;。这显然不是很好,因为这意味着您完全失去了类型检查,并且最终可能会将任何内容添加到列表中。所以出于这个原因,我不会推荐这种方法。

  2. 使ParentContainer&lt;&gt; 实现一个标记接口。例如:

    public interface IParentContainer
    {
    }
    
    public abstract class ParentContainer<T> : IParentContainer
        where T: ParentFoo
    {
        //snip
    }
    

    现在您可以拥有这样的列表:

    var containers = new List<IParentContainer>
    {
        new ChildContainer(),
        new ChildContainer2()
    };
    

【讨论】:

    【解决方案2】:

    除非我误解了这个问题,否则你想要这样的东西......

    public void DoStuffWith<T>(List<ParentContainer<T>> containers) where T : Parentfoo
    {
         //TODO: implement
    }
    

    这适用于 ... 类型的对象

    List<ParentContainer<ParentFoo>>
    List<ParentContainer<ChildFoo>>
    

    在哪里 ChildFoo : ParentFoo

    并解决了“List&lt;ParentContainer&lt;ParentFoo&gt;&gt; 未实现IEnumerable&lt;ParentContainer&lt;ChuldFoo&gt;&gt;”的问题,我怀疑这是您看到的编译器。

    更进一步,例如 ....

    public void DoStuffWith<ContainerT,ElementT>(List<ContainerT<ElementT>> containers) 
      where ContainerT : ParentContainer 
      where ElementT : Parentfoo
    {
         //TODO: implement
    }
    

    ... 可能会使问题过于复杂,但我怀疑这是您想要实现的目标。

    在这一点上,我会质疑您拥有的数据结构并给它们一些共同的父级,例如...

    public class ParentContainer<T> : IEnumerable<T> { ... }
    public class ChildContainer<T> : ParentContainer<T>, IEnumerable<T> { ... } 
    

    由于两者都实现了 IEnumerable,您现在可以这样做...

    public void DoStuffWith<T>(IEnumerable<T> containers) where T : ParentFoo
    {
         //TODO: implement
    }
    

    这完全避免了关注集合类型的需要。

    【讨论】:

    • 我不是在要求投票……只是想结束这个问题。记错了!
    • 我已经编辑了答案以反映问题的变化。
    • @War 这正是我想要的。但是您的示例并不完全正确。因为where T : ChildContainer 仅适用于一个特定的 ChildContainer
    • 新版本有帮助吗?
    • @war 但我有一个 ChildContainers 列表...我无法将 List&lt;ChildContainerX&gt; 传递给该方法
    【解决方案3】:
    class Program
    {
        static void Main(string[] args)
        {
    
            List<ParentContainer<ChildFoo>> ca = new List<ParentContainer<ChildFoo>>();
    
            ProcessContainers processor = new ProcessContainers();
    
            ca.Add(new ChildContainerA { fooList = new List<ChildFoo>() });
            ca.Add(new ChildContainerA { fooList = new List<ChildFoo>() });
            ca.Add(new ChildContainerA { fooList = new List<ChildFoo>() });
            ca.Add(new ChildContainerB { fooList = new List<ChildFoo>() });
    
            processor.Process(ca);
        }
    }
    
    
    public abstract class ParentContainer<T> where T: ParentFoo
    {
        public List<T> fooList;
    }
    
    //Let there be many different ChildContainers with different types.
    public class ChildContainerA : ParentContainer<ChildFoo>
    {
    }
    public class ChildContainerB : ParentContainer<ChildFoo>
    {
    }
    
    public class ProcessContainers
    {
        public void Process<T>(List<ParentContainer<T>> childContainers) where T : ParentFoo
        {
            foreach(var item in childContainers)
            {
                foreach(var foo in item.fooList)
                {
                    foo.Porcess();
                }
            }
        }
    }
    
    public abstract class ParentFoo
    {
        public string name;
    
        public abstract void Porcess();
    }
    
    public class ChildFoo : ParentFoo
    {
        public override void Porcess()
        {
            //Do some processing
        }
    }
    

    【讨论】:

    • ProcessContainers 类可用于处理其中包含 foo 列表的许多容器。希望这会有所帮助
    • 希望这会有所帮助
    猜你喜欢
    • 1970-01-01
    • 2021-02-16
    • 1970-01-01
    • 2016-12-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-30
    相关资源
    最近更新 更多