简体   繁体   English

如何投放清单 <Object> 列出 <Foo> 当foo是类型变量并且我不知道类型时

[英]How can I cast List<Object> to List<Foo> when foo is a type variable and I don't know the type

I have a situation where through reflection I have List>object<. 我有一种情况,通过反射我得到了List> object <。 I also have a reflected method that takes List>foo<. 我也有一个采用List> foo <的反射方法。 List>object< contains a whole bunch of foos, but List>object< cannot be directly casted to List>foo<. List> object <包含一堆foo,但是List> object <无法直接转换为List> foo <。 I have a Type variable that contains foo, but do not know it at compile time. 我有一个包含foo的Type变量,但在编译时不知道。 My code looks something like below 我的代码如下所示

var ASM = Assembly.LoadFrom("foo.dll");
var bar = List<string>() { /*A whole bunch of string literals*/ };

var FooType = ASM.GetType("Foo")
List<object> foos = new List<object>; 
foreach (var str in bar)
{
   foos.add(Activator.CreateInstance(FooType, new [] {str}));
}

var Flags = BindingFlags.Static | BindingFalgs.Public;
FooType.GetMethod("DoSomethingWithAListOfFoo", Flags).Invoke(null, foos)

At this point I'm told that a List cannot be converted to a List via a runtime exception 此时,我被告知无法通过运行时异常将列表转换为列表

Reflection go you into this mess, so you're going to need reflection to get you out, only it's going to be deeper darker nastier reflection. 反射会使您陷入混乱,因此您将需要反射才能使自己脱身,这只会是更深的更暗的反射。 Reflection of Generic Methods. 通用方法的反思。


So lets say you've aleady got your foos variable populated. 因此,可以说您已经将foos变量填充进去了。 It's a list of objects. 这是对象列表。 How do you cast a list of something to a list of something else? 您如何将某事物列表转换为其他事物列表? Cast! 投! In your instance, you want Cast but you don't have access to that from what I understand, so we need to create an instance of the Cast method. 在您的实例中,您需要Cast,但根据我的理解您无权访问它,因此我们需要创建Cast方法的实例。 First we need to get the Generic Cast method 首先,我们需要获得Generic Cast方法

var GenericCastMethod = typeof(System.Linq.Enumerable)
  .GetMethod("Cast", BindingFlags.Public | BindingFlags.Static);

Now we need to make a type specific cast method 现在我们需要制作一个特定类型的强制转换方法

var SpecificCastMethod = GenericCastMethod.MakeGenericMethod(FooType);

Finally, we need to call this on your list 最后,我们需要在您的清单中称呼它

var FoosOfTypeFoo = SpecificCastMethod.Invoke(null, new object[] { foos });

You can now use FoosOfTypeFoo as an IEnumerable . 现在,您可以将FoosOfTypeFoo 用作IEnumerable This if of course, not what you want. 这当然不是您想要的。 So we need to do the same thing on ToList method. 因此,我们需要对ToList方法执行相同的操作。 Sparing you the gory details, all put together it should look like this 为您省去所有细节,所有这些看起来应该像这样

var GenericCastMethod = typeof(System.Linq.Enumerable)
  .GetMethod("Cast", BindingFlags.Public | BindingFlags.Static);
var SpecificCastMethod = GenericCastMethod.MakeGenericMethod(FooType);
var IEnumerableOfFoo = SpecificCastMethod.Invoke(null, new object[] { foos });

var GenericToListMethod = typeof(System.Linq.Enumerable)
  .GetMethod("ToList", BindingFlags.Public | BindingFlags.Static);
var SpecificToListMethod = GenericToListMethod .MakeGenericMethod(FooType);
var ListOfFoo = SpecificToListMethod .Invoke(null, new object[] { FoosOfTypeFoo });

The moral of this story is that black magic code begets fouler darker black magic code. 这个故事的寓意是,黑魔法代码会生出更深的黑魔法代码。

Don't use Reflection, use an ArrayList (no, really) 不要使用反射,请使用ArrayList(不,真的)

Do you remember the old type, ArrayList ? 您还记得旧类型ArrayList吗? Nobody uses it much any more; 没有人再使用它了。 it's just like List<object> . 就像List<object> But there is one key difference: ArrayList has a ToArray(Type) method (not a ToArray<T> method, since generics didn't exist back then). 但是有一个关键的区别:ArrayList有一个ToArray(Type)方法(不是ToArray<T>方法,因为那时泛型不存在)。 So you easily can make an array with any type, as long as you can get a Type object for them. 因此,只要可以为其获取Type对象,就可以轻松地创建具有任何类型的数组。

Here are two solutions that take advantage of this feature. 这里有两个利用此功能的解决方案。

Solution 1. One line change. 解决方案1.更改一行。

If DoSomethingWithAListOfFoos accepts an IEnumerable<Foo> (and doesn't require it to be a List<Foo> ), you can just use this: 如果DoSomethingWithAListOfFoos接受IEnumerable<Foo> (并且不需要将其作为List<Foo> ),则可以使用以下代码:

FooType.GetMethod("DoSomethingWithAListOfFoo", Flags)
    .Invoke(
        null, 
        new ArrayList(foos).ToArray(FooType)  //Magic!!!
    );

Easy enough, right? 很容易,对吧? You didn't even have to reflect anything. 您甚至不需要反映任何内容。

Solution 2. Extension method. 解决方案2.扩展方法。

If DoSomethingWithAListOfFoos truly requires a List<Foo> we have a little more work to do because we have to construct the generic list. 如果DoSomethingWithAListOfFoos确实需要List<Foo>我们还有更多工作要做,因为我们必须构造通用列表。

First, add this extension method somewhere in your code: 首先,将此扩展方法添加到代码中的某个位置:

static public ICollection ToGenericList(this ICollection input, Type itemType)
{
    return (ICollection) typeof(List<>)
        .MakeGenericType(itemType)
        .InvokeMember(
            null, 
            BindingFlags.CreateInstance, 
            null, 
            null, 
            new object[] { new ArrayList(input).ToArray(itemType) }
        );
}

This works because every List<T> comes with a constructor that will accept an array. 之所以可行,是因为每个List<T>都带有一个接受数组的构造函数。 And we already figured out how to make the array very easily. 而且我们已经想出了如何轻松制作阵列的方法。 We just locate the right constructor and pass it in, and the runtime does the rest. 我们只需要找到正确的构造函数并将其传递,剩下的就由运行时完成。

Now just call it like this: 现在就这样称呼它:

FooType.GetMethod("DoSomethingWithAListOfFoo", Flags)
    .Invoke(
        null, 
        new foos.ToGenericList(FooType)   //Our new extension method
    );

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

相关问题 如何将对象转换为C ++ / CLI中不知道其类型参数的通用列表? - How can I cast an Object to a generic List I don't know the type parameter of in C++/CLI? 如何隐式转换列表 <Foo> 列出 <Bar> 鉴于定义了强制转换运算符? - How can I implicitly convert List<Foo> to List<Bar> given that there's a cast operator defined? 为什么我不能将List <List <Foo >>传递给IEnumerable <IEnumerable <Foo >> - Why can't I pass a List<List<Foo>> to an IEnumerable<IEnumerable<Foo>> 如何设置列表<foo>值为 List 的 object 的字段<dynamic></dynamic></foo> - How can I set a List<foo> field of an object with the value of List<dynamic> 我不知道的演员类型是什么 - Cast type which i don't know yet what is it 如果我不知道正确的类型,如何反序列化对象? - How can I deserialize an object if I don't know the right type? 如何在 List 中转换对象类型<t> 。除了 - How to cast the object type in List<t>.Except 为什么我不能转换 Foo<t?> 给富<t></t></t?> - Why can I not convert Foo<T?> to Foo<T> 如何将List转换为从List继承的类型 <T> ? - How can I cast a List into a type which inherits from List<T>? 当我只能访问列表的对象并且不知道type参数时,如何遍历列表的项目? - How to iterate over items of a list when I only have access to the object of that list and dont know the type parameter?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM