将具有通用参数的项目列表拆分为每个通用类型的单独列表

Split a list of items with generic parameters into separate lists of each generic type

我正在尝试解决一个问题,我想根据列表中项目的通用参数类型拆分列表。每种类型的类型可能不同。下面是一些演示代码,用于尝试解释我需要做什么。

注意:此代码不会按原样编译,因为类型 T 未在 FindDerivedItemsAndCallForEachT 中定义。

using System.Collections.Generic;
using System.Linq;

public class BaseItem
{
}

public class DerivedItem<T> : BaseItem
{
}

public class Test
{
    public void FindDerivedItemsAndCallForEachT(List<BaseItem> list)
    {
        var derivedItems = from d in list.OfType<DerivedItem<T>>()
            select d;

        var listsOfDerivedItems = from d in derivedItems
            group d by d.GetType() into g
            select g.ToList();

        foreach (var listOfDerivedItem in listsOfDerivedItems)
        {
            HandleForTypeT(listOfDerivedItem);
        }
    }


    public void HandleForTypeT<T>(List<DerivedItem<T>> derivedList)
    {
        // do something with the provided list.
    }
}

所以我有一个 BaseItems 列表,其中可能包含一些采用通用参数的派生项目。对于列表中的每个项目,此参数可能不同。我想要做的是找到列表中的所有派生类型,然后将它们拆分为每个泛型类型的单独列表。然后获取每个列表并将它们传递给另一个方法进行处理。

我的方法在这里可能完全错误,所以请随意走另一条路。

我的问题和this question几乎一样。对我而言,不同之处在于我不想在列表项上调用方法,而是将它们作为列表传递给另一个方法。每个类型T的派生项需要一起处理

我有一个"solution"。它使用反射,但(正如@Jon 所指出的)真正的问题可能是架构本身。我的解决方案可能会有所不同,因为方法 HandleForType< T > 实际上将位于类型 T 的单独 class 中,并且能够过滤 List< BaseItem > 以查找所有 Derived< T > 本身。

请随时改进代码,因为它可能会帮助其他尝试做类似事情的人。

参考文献:
SO Question that got me on the right track
Related MSDN documentation

using System;
using System.Collections.Generic;
using System.Linq;

using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace UnitTestProject1
{
    [TestClass]
    public class CheckFindDerivedItemsAndCallForEachT
    {
        [TestMethod]
        public void TestMethod1()
        {
            var list = new List<BaseItem>();
            list.Add(new DerivedItem<string>());
            list.Add(new DerivedItem<int>());

            var test = new Test();

            test.FindDerivedItemsAndCallForEachT(list);
        }
    }

    public class BaseItem
    {
    }

    public class DerivedItem<T> : BaseItem
    {
    }

    public class Test
    {
        public void FindDerivedItemsAndCallForEachT(List<BaseItem> list)
        {
            var derivedItems = from d in list
                               where d.GetType().IsGenericType
                               && d.GetType().GetGenericTypeDefinition() == typeof(DerivedItem<>)
                               select d;

            var listsOfDerivedItems = from d in derivedItems
                                      group d by d.GetType() into g
                                      select g.ToList();

            // create generic type definition for lists
            var listGenericDefinition = typeof(List<>);

            foreach (var listOfDerivedItem in listsOfDerivedItems)
            {
                // all the lists should have at least one member which will be of the type that we need.
                Type itemType = listOfDerivedItem[0].GetType();
                Type listType = listGenericDefinition.MakeGenericType(itemType);

                // note use of dynamic is important.
                dynamic castList = Activator.CreateInstance(listType);
                foreach (dynamic item in listOfDerivedItem)
                {
                    castList.Add(item);
                }

                HandleForTypeT(castList);
            }
        }

        public void HandleForTypeT<T>(List<DerivedItem<T>> derivedList)
        {
            // do something with the provided list.
        }
    }
}