转换IEnumerable<;A>;到IEnumerable<;B>;而在编译时不知道类型
本文关键字:gt lt IEnumerable 编译 类型 不知道 转换 | 更新日期: 2023-09-27 18:22:03
我有两种类型:我们称它们为A和B。可以使用适配器方法将A转换为B。
然后,我在List<A>
中有一个a的集合(它可以是任何支持IEnumerable<A>
的集合类型)。
我现在想从IEnumerable<A>
转换为IEnumerable<B>
。我知道A和B各自的Type
,我有一个将A转换为B的方法,但我的方法和/或类本身没有模板化,因此我无法访问模板类型;例如CCD_ 6中的T。
我实际上想写这个ConvertCollection方法,我知道"from"的类型是IEnumerable<{something}>
:
object ConvertCollection(object from, Type fromType, Type toType, Converter converter);
我的转换器看起来像这样:
delegate object Converter(object from);
我的尝试把我留在这里:
object ConvertCollection(object from, Type fromType, Type toType, Converter converter)
{
return ((IEnumerable<object>)from).Select(converter);
}
这部分起作用。如果我这样称呼它
ConvertCollection(new List<A>() { new A() }, typeof(A), typeof(B), AToBConverter);
返回的集合确实包含B的集合,但集合本身的类型是IEnumerable<object>
,而不是IEnumerable<B>
,因为我不知道如何转换为IEnumerable<{toType}>
。(这很重要,因为结果需要序列化)。
我可以从另一端攻击它,并创建正确的返回类型,如下所示:
var result = Activator.CreateInstance(typeof(List<>).MakeGenericType(toType));
// TODO: populate result here
return result;
但问题是,要实现TODO部分,我需要调用List<>方法,但由于Co/ContraVariance规则,我不能将其强制转换为任何类型的List<>
,所以即使我知道该类型支持List<>
方法,我也无法使用它们来填充列表;例如使用Add()。
有没有一种方法可以在不使用"动态"和不进行过多反思的情况下做到这一点?我知道我可以通过反射找到并调用Add()方法,但似乎没有必要。
.NET 4.0 BTW
-澄清
正如Euphoric正确推测的那样,我试图传达以上内容,但非常失败,我在运行时知道类型A和B,但在编译时不知道它们。因此,直接使用泛型不是一种选择。我知道集合(提供的和必须返回的)实现了通用IEnumerable<>
。这一切都是固定的,超出了我的控制范围。(我相应地调整了标题)。
**编辑2:修复了一些导致<>
不显示的格式设置(很容易意外忽略反勾号!)
使用LINQ Select
方法:
var result = listA.Select(a => Converter(a));
既然您使用的是.NET 4.0,那么您确实应该避免使用object
并使用泛型。
我确定的解决方案是使用反射来调用Enumerable.Cast<>
方法,将结果集合从IEnumerable<object>
强制转换为正确的IEnumerable<>
类型。我从这个问题的答案中得到了这个想法:将IEnumerable转换为IEnumerable<T>当T不是';直到运行时才知道。似乎只涉及很少的性能惩罚。
因此,完整的答案是:
object ConvertCollection(object from, Type fromType, Type toType, Converter converter)
{
var partialResult = ((IEnumerable<object>)from).Select(converter);
var castMethod = typeof(Enumerable).GetMethod("Cast").MakeGenericMethod(toType);
return castMethod.Invoke(null, new[] { partialResult });
}
也许是这样的?
IEnumerable<TTo> ConvertCollection<TFrom,TTo>(object from, Converter converter)
{
return ((IEnumerable<TFrom>)from).Select(a=>(TTo)converter(a)).ToList();
}
然后你可以简单地称之为:
ConvertCollection<A,B>(new List<A>() { new A() }, AToBConverter);