具有常用方法但没有继承的类的通用扩展方法

时间:2013-11-27 21:29:45

标签: c# generics

我正在使用我的.Net 3.5项目中的一个COM库,它有一堆(大约20-30个)集合类型接口。这些类中的每一个都向事物公开名为Count的属性以及名为ItemByIndex(int)GetEnumerator()的方法(类型为System.Collections.IEnumerator)。

但是,每个接口都是自己实现的,而不是在公共父类中实现。

有没有办法编写将集合对象转换为List<>?的通用扩展方法?这就是我目前正在做的事情,但我复制并粘贴了大约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;
}

4 个答案:

答案 0 :(得分: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;
}

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

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

答案 1 :(得分: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);

答案 2 :(得分:0)

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

答案 3 :(得分:0)

您可以包装库类(使用http://en.wikipedia.org/wiki/Adapter_pattern),并使它们实现IList接口。