2013-11-27 74 views
1

我正在与我的.net 3.5项目中有一堆(约20-30)集合类型接口的COM库。这些类中的每一个都公开了名为Count的属性以及名为ItemByIndex(int)GetEnumerator()(其类型为System.Collections.IEnumerator)的方法。通用扩展方法,但通用方法,但没有继承

但是,这些接口中的每一个接口都是自己实现的,而不是共同的父类。

有没有办法编写一个通用的扩展方法,将集合对象转换为列表<>?这是我目前正在做的,但我有20个左右的方法复制和粘贴。

public static List<iml.IManDocument> ToList(this iml.IManDocuments source) 
{ 
    List<iManDocument> results = new List<iManDocument>(source.Count); 
    for (int i = 1; i <= source.Count; i++) 
    { 
     results.Add((iml.IManDocument)source.ItemByIndex(i)); 
    } 
    return results; 
} 

回答

1

理想情况下,您应该让您的类型实现IList<T>IReadOnlyList<T>。不过,我猜你不能这样做......

您可以使用内置的方法(利用的事实,他们是IEnumerable)做到这一点:

var list = myIManDocuments.Cast<IManDocument>().ToList(); 

你可以用它做dynamic,但是这有缺点,最大的一个问题是你没有得到任何编译时检查你是否在兼容类型中执行此操作。

public static List<T> ToList<T>(dynamic source) 
{ 
    List<T> results = new List<T>(source.Count); 
    for (int i = 1; i <= source.Count; i++) 
    { 
     results.Add(source.ItemByIndex(i)); 
    } 
    return results; 
} 

使用像:

var list = MyUtil.ToList<IManDocument>(myIManDocuments); 
0

List有一个接受IEnumerable参数的构造函数。由于IEnumerable只具有(通用的)GetEnumerator,因此您可以轻松地使您的接口从IEnumerable(通用接口)派生并使用List构造函数。

2

不幸的是,您不能在现有方法的基础上添加扩展方法,也无法将接口动态添加到适合这些接口的类型中(两者都是非常有用的东西)。

一个选项是为object添加扩展方法,并使用反射来确定是否存在所需的方法和属性。

public static List<iml.IManDocument> ToListByReflection(this object source) 
{ 
    var type = source.GetType(); 
    var countProperty = type.GetProperty("Count"); 
    var itemByIndexMethod = type.GetMethod("ItemByIndex", new[] { typeof(int) }); 

    if (countProperty == null || itemByIndexMethod == null) 
    { 
     throw new Exception("Type does not offer required methods."); 
    } 

    var count = countProperty.GetValue(source); 
    var results = new List<iManDocument>(count); 
    for (int i = 1; i <= count; i++) 
    { 
     results.Add((iml.IManDocument)itemByIndexMethod.Invoke(source, new object[] { i }); 
    } 

    return results; 
} 

为了获得更好的性能,您甚至可以缓存每种不同类型的属性和方法信息。

但只是写一个像你一样的方法在我看来真的是更好的选择。它更清晰,它在编译时是类型安全的(值得很多!),并且比反射更快。这只是一次写入每种类型,而且大部分都是复制粘贴。