繁体   English   中英

将 IEnumerable 转换为实现 IEnumerable 的类型

[英]Convert IEnumerable to type that implements IEnumerable

给定:

如果您有以下值:

  1. Type type
  2. IEnumerable enumerable

并且满足以下条件:

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

一般问题:

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

背景:

System.Collections大多数类型都有一个像Example(ICollection)这样的构造函数,如果type有一个像这样的构造函数,那么执行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
}

这是使用优质旧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

此技术允许您避免Reflection确定要创建和调用哪个通用MethodInfo来创建数组。 该框架为您做到了。

请求的解决方案应该能够处理任何类型的容器,包括一个波纹管? 这似乎很难,不是说不可能。 填充此容器的唯一方法是通过Populate方法,但一般解决方案如何知道?

public class TupleList<T1, T2, T3> : IEnumerable<Tuple<T1, T2, T3>>
{
    private List<Tuple<T1, T2, T3>> _list = new List<Tuple<T1, T2, T3>>();

    public void Populate(T1 item1, T2 item2, T3 item3)
    {
        _list.Add(Tuple.Create(item1, item2, item3));
    }

    public Tuple<T1, T2, T3> this[int index] { get => _list[index]; }

    public IEnumerator<Tuple<T1, T2, T3>> GetEnumerator()
    {
        return _list.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return this.GetEnumerator();
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM