C# 按实现拆分接口列表

C# split List of interface by implementations

我需要拆分 List<IInterface> 以获得 IInterface 的具体实现列表。 我怎样才能以最佳方式做到这一点?

        public interface IPet { }
        public class Dog :IPet { }
        public class Cat : IPet { }
        public class Parrot : IPet { }

        public void Act()
        {
            var lst = new List<IPet>() {new Dog(),new Cat(),new Parrot()};
            // I need to get three lists that hold each implementation 
            // of IPet: List<Dog>, List<Cat>, List<Parrot>
        }

你可以使用 linq 来过滤你正在寻找的类型,但是如果你试图将事情分解成所有实现的任何列表,这可能很棘手,你必须使用倒影

var dogs = lst.Where(x => x is Dog).ToList()
var cats = lst.Where(x => x is Cat).ToList()
var parrots = lst.Where(x => x is Parrot).ToList()

您可以按类型执行 GroupBy

var grouped = lst.GroupBy(i => i.GetType()).Select(g => g.ToList()).ToList()

如果您想要按类型分类的字典,您可以这样做:

var grouped = lst.GroupBy(i => i.GetType()).ToDictionary(g => g.Key, g => g.ToList());
var dogList = grouped[typeof(Dog)];

或者正如 Tim 在评论中建议的那样:

var grouped = lst.ToLookup(i => i.GetType());

您可以使用 OfType 扩展名:

var dogs = lst.OfType<Dog>().ToList();
var cats = lst.OfType<Cat>().ToList();
var parrots = lst.OfType<Carrot>().ToList();

虽然这里已经有了答案。他们的实现都使用 linq 并创建许多新列表和数据传递,这里是一个更高效但不那么漂亮的单传递实现。 这里有一些代码将我的方法与此处的所有其他方法进行比较:

首先输出:

使用 heinzbeinz 花费的时间:6533

使用 Arturo Menchaca 花费的时间:6450

使用 johnny 5 花费的时间:5261

使用 Matt Clark(无 linq)花费的时间:2072

          Stopwatch sw = new Stopwatch();
        sw.Start();
        for (int k = 0; k < 1000000; k++)
        {
            // heinzbeinz
            var petLists = pets.GroupBy(i => i.GetType()).Select(g => g.ToList()).ToList();
        }
        sw.Stop();
        Console.WriteLine($"Time taken using heinzbeinz: {sw.ElapsedMilliseconds}");

        sw.Reset();
        sw.Start();
        for (int k = 0; k < 1000000; k++)
        {
            // Arturo Menchaca
            var dogs = pets.OfType<Dog>().ToList();
            var cats = pets.OfType<Cat>().ToList();
            var parrots = pets.OfType<Parrot>().ToList();
        }
        sw.Stop();
        Console.WriteLine($"Time taken using Arturo Menchaca: {sw.ElapsedMilliseconds}");

        sw.Reset();
        sw.Start();
        for (int k = 0; k < 1000000; k++)
        {
            // johnny 5
            var dogs = pets.Where(x => x is Dog).ToList();
            var cats = pets.Where(x => x is Cat).ToList();
            var parrots = pets.Where(x => x is Parrot).ToList();
        }
        sw.Stop();
        Console.WriteLine($"Time taken using johnny 5: {sw.ElapsedMilliseconds}");

        sw.Reset();
        sw.Start();
        for (int k = 0; k < 1000000; k++)
        {
            // Matt Clark
            var dogs = new List<Dog>();
            var cats = new List<Cat>();
            var parrot = new List<Parrot>();
            foreach (var pet in pets)
            {
                if (pet is Dog)
                {
                    dogs.Add(pet as Dog);
                }
                if (pet is Cat)
                {
                    cats.Add(pet as Cat);
                }
                if (pet is Parrot)
                {
                    parrot.Add(pet as Parrot);
                }
            }
        }
        sw.Stop();
        Console.WriteLine($"Time taken using Matt Clark (no linq): {sw.ElapsedMilliseconds}");

你最好使用

var dogs = lst.OfType<Dog>().ToList()
var cats = lst.OfType<Cat>().ToList()
var parrots = lst.OfType<Parrot>().ToList()