代码之家  ›  专栏  ›  技术社区  ›  OwenP

有没有办法将泛型列表转换为接口/基类类型列表?

  •  3
  • OwenP  · 技术社区  · 17 年前

    我试图向某人展示界面在他们创造的疯狂情况下的用途。它们在列表中有几个不相关的对象,需要对每个对象中的两个字符串属性执行操作。我要指出的是,如果他们将属性定义为接口的一部分,他们可以使用接口对象作为作用于它的方法参数的类型;例如:

    void PrintProperties(IEnumerable<ISpecialProperties> list)
    {
        foreach (var item in list)
        {
            Console.WriteLine("{0} {1}", item.Prop1, item.Prop2);
        }
    }

    这看起来很好,但是需要处理的列表没有(也不应该)以接口作为类型参数来声明。但是,您似乎无法强制转换为其他类型参数。例如,这失败了,我不明白为什么:

    using System;
    using System.Collections.Generic;
    
    namespace ConsoleApplication2
    {
        class Program
        {
            static void Main(string[] args)
            {
                List<Test> myList = new List<Test>();
                for (int i = 0; i < 5; i++)
                {
                    myList.Add(new Test());
                }
    
                PrintList((IEnumerable<IDoSomething>)myList);
            }
    
            static void PrintList(IEnumerable<IDoSomething> list)
            {
                foreach (IDoSomething item in list)
                {
                    item.DoSomething();
                }
            }
        }
    
        interface IDoSomething
        {
            void DoSomething();
        }
    
        public class Test : IDoSomething
        {
            public void DoSomething()
            {
                Console.WriteLine("Test did it!");
            }
        }
    }

    可以 使用 Enumerable.Cast<T> 成员来做这件事,但我正在寻找一种可能在.NET2.0中也能工作的方法。这似乎是可能的;我错过了什么?

    5 回复  |  直到 17 年前
        1
  •  5
  •   James Curran    17 年前

    问题在于方法,而不是它的调用方式。。。。。

    void PrintProperties<SP>(IEnumerable<SP> list) where SP: ISpecialProperties
    {
        foreach (var item in list)
        {
            Console.WriteLine("{0} {1}", item.Prop1, item.Prop2);
        }
    }
    
        2
  •  5
  •   Jon Skeet    17 年前

    它失败的原因是因为泛型在C#中还没有表现出差异。

    至于IEnumerable的修复<T>,但是,请尝试以下方法:

    public static IEnumerable<TBase> SafeConvert<TBase, TDerived>(IEnumerable<TDerived> source)
        where TDerived : TBase
    {
        foreach (TDerived element in source)
        {
            yield return element; // Implicit conversion to TBase
        }
    }
    

    编辑:对于这种特殊情况,另一个现有的答案比上面的答案更好,但是如果您确实需要“转换”序列,我将把它作为一件通常有用的事情留在这里。

        3
  •  1
  •   tpower    17 年前

    你可以用一个 foreach 在你的名单上。这个

    List<Test> myList = new List<Test>();
    for (int i = 0; i < 5; i++)
    {
       myList.Add(new Test());
    }
    
    foreach (IDoSomething item in myList)
    {
       item.DoSomething();
    }
    
        4
  •  1
  •   Constantin    17 年前

    你想要的是所谓的“接口协方差”,目前C#不支持。你可以在网上看到 Eric Lippert's blog .

        5
  •  -1
  •   Jeff Kotula    17 年前

    推荐文章