【问题标题】:How do I convert a List<interface> to List<concrete>?如何将 List<interface> 转换为 List<concrete>?
【发布时间】:2011-05-16 15:37:54
【问题描述】:

我有一个接口定义为:

public interface MyInterface {
     object foo { get; set; };
}

以及实现该接口的类:

public class MyClass : MyInterface {
     object foo { get; set; }
}

然后我创建一个返回 ICollection 的函数,如下所示:

public ICollection<MyClass> Classes() {
    List<MyClass> value;

    List<MyInterface> list = new List<MyInterface>(
        new MyInterface[] {
            new MyClass {
                ID = 1
            },
            new MyClass {
                ID = 1
            },
            new MyClass {
                ID = 1
            }
        });

    value = new List<MyClass>((IEnumerable<MyClass>) list);

    return value;
}

它会编译但会抛出一个

无法转换类型的对象 'System.Collections.Generic.List1[MyInterface]' to type 'System.Collections.Generic.IEnumerable1[MyClass]'。

异常。我做错了什么?

【问题讨论】:

    标签: c# generics interface


    【解决方案1】:

    一般情况下,List&lt;MyInterface&gt; 不能转换为 List&lt;MyClass&gt;,因为第一个列表可能包含实现 MyInterface 但实际上不是 MyClass 类型的对象。

    但是,由于在您的情况下您知道如何构建列表并且可以确定它仅包含 MyClass 对象,因此您可以使用 Linq 执行此操作:

    return list.ConvertAll(o => (MyClass)o);
    

    【讨论】:

    • 这将适用于 .Net 2.0+ 而不仅仅是 LINQ,因为 System.Collections.Generic.List 直接支持 ConvertAll()。
    • 谢谢,@Ritch。我以为ConvertAll是一个Linq方法,但我懒得去查了。
    • 其实,如果你确定你的列表只包含MyClass对象,你应该使用Enumerable.Cast&lt;TResult&gt;方法,如果序列中的一个元素不能被强制转换成你会得到一个InvalidCastException MyClass.
    • @PaoloMoretti:谢谢 - 您的方法节省了很多精力。我正在使用 Telerik wpf 组件,在 RadDataFilter 中,返回值是一个接口列表,我必须使用类型转换和字符串匹配开关进行长 foreach 以及其他操作。现在我可以使用 linq。 :)
    【解决方案2】:

    但是List&lt;MyInterface&gt; 绝对不是List&lt;MyClass&gt;

    思考:

    interface IAnimal { }
    
    class Cat : IAnimal { }
    class Dog : IAnimal { }
    
    var list = new List<IAnimal> { new Cat(), new Dog() };
    

    然后

    var cats = (List<Cat>)list;
    

    荒谬!

    还有,

    var cats = list.Cast<Cat>();
    

    荒谬!

    进一步

    var cats = list.ConvertAll(x => (Cat)x);
    

    荒谬!

    相反,你可以说

    var cats = list.OfType<Cat>();
    

    【讨论】:

    • 我明白了。我很困惑,因为您可以将接口强制转换为它的具体类。谢谢。
    【解决方案3】:

    你可以使用Cast&lt;&gt;扩展方法:

    return list.Cast<MyClass>();
    

    【讨论】:

    • 你能补充一些细节吗?
    【解决方案4】:

    我发现 Automapper 对于将接口转换为具体类非常有用。

    【讨论】:

      【解决方案5】:

      这是可能的,这就是泛型发光的地方! 这是一个简单的例子:

      public interface ICountable
      {
           int Count { get; set; }
      }
      
      public class PopularName : ICountable
      {
          public string Name { get; set; }
          public int Count { get; set; }
      }
      
      public class PopularSize : ICountable
      {
           public int Size { get; set; }
           public int Count { get; set; }
      }
      

      现在你需要像这样声明你的方法(或你的类)泛型:

      public bool HasAnyValue<T>(List<T> countableModel) where T : ICountable
      {
          return countableModel.Count > 0;
      }
      

      【讨论】:

        猜你喜欢
        • 2012-02-14
        • 2016-06-06
        • 1970-01-01
        • 2013-09-21
        • 2020-11-27
        • 2020-01-11
        • 2023-01-19
        相关资源
        最近更新 更多