首页 > 解决方案 > 将 IEnumerable 转换为实现 IEnumerable 的类型

问题描述

给定:

如果您有以下价值观:

  1. Type type
  2. IEnumerable enumerable

并且满足以下条件:

  1. typeof(IEnumerable).IsAssignableFrom(type)
  2. enumerable.All(element => element.GetType() == type.GetElementType())

一般问题:

type是否可以通过反射创建一个包含所有元素的实例enumerable

背景:

中的大多数类型System.Collections都有一个类似的构造函数Example(ICollection),而 iftype有一个这样的构造函数,它做起来很简单直接Activator.CreateInstance(type, enumerable)。但是对于像这样的类型Dictionary<TKey, TValue>,它并不是那么简单。我想到的唯一解决方案是这样的:

var dictionary = (IDictionary) Activator.CreateInstance(type);
var elementType = enumerable.First().GetType();
var key = elementType.GetProperty("Key");
var value = elementType.GetProperty("Value");

foreach (var element in enumerable)
{
   dictionary.Add(key.GetValue(element), value.GetValue(element));
}

我更愿意接受这种KeyValuePair<TKey, TValue>实现包含属性的接口的解决方案KeyValue因此您可以说:

var keyValuePair = (IKeyValuePair) element;
dictionary.Add(keyValuePair.Key, keyValuePair.Value);

而不是依靠反射来获取上述属性值。

此解决方案仅适用于System.Collections强烈遵守所述类型定义的类型或自定义类型。

具体问题:

有没有一种更优雅的方法可以转换enumerable为类型type,也可以解释边缘情况MyCollection : ICollection,比如我们不知道类型定义的情况?

更新:

这是一个例子:

var original = new Dictionary<int, string>
{
   //values
};

var type = original.GetType();
var enumerable = original.AsEnumerable();

var copy = (Dictionary<int, string>) DoSomeMagic(type, enumerable);

object DoSomeMagic(Type type, IEnumerable enumerable)
{
   //Add magic here
}

标签: c#reflectioncollections

解决方案


这是使用 good old 为数不多的几个原因之一ArrayList

System.Array ConvertUnknownIEnumerableToArray(IEnumerable ienumerable, Type type)
{
    var list = new ArrayList();
    foreach (var i in ienumerable) list.Add(i);
    return list.ToArray(type);
}

上面创建了一个强类型数组(命名array),其中包含任何可枚举的命名中的具体对象ienumerable。当然,数组实现ICollection.

此技术允许您避免反射确定要创建和调用哪个泛型 MethodInfo 来创建数组。该框架为您完成。


推荐阅读