简体   繁体   English

包含c#中列表的动态类型

[英]Dynamic type with lists in c#

I have a little problem for you guys. 我有一点问题。

I would like to do this: 我想这样做:

Type[] classes = new Type[]{ Class1, Class2 };

foreach(Type t in classes){   
  List<t> list = new List<t>(); 
}

Is there some way to do this? 有办法做到这一点吗?

You cannot cast to a generic type at runtime, because the type in the generic needs to be resolved at compile time. 不能在运行时转换为泛型类型,因为泛型中的类型需要在编译时解析。

You can create a generic type in a dynamic manner using reflection, but unless you hard-code the cast, all you get in return is an object. 可以使用反射以动态方式创建泛型类型,但除非您对强制转换进行硬编码,否则您获得的所有内容都是对象。

I cannot really tell what it is you want, I have to agree with a comment this is an XY problem . 我不能真正说出你想要的是什么,我不得不同意这是一个XY问题 I would be inclined to make the presumptuous statement that there is a design issue somewhere that this is trying to solve, instead of addressing the design issue directly, or asking the question of what you are trying to achieve directly. 我倾向于做出这样一种冒昧的陈述:这是一个设计问题,它试图解决,而不是直接解决设计问题,或者询问你想要直接实现的问题。


You can use the following code to create the type, then the dynamic type can be used to duck type the various members of List<T> without knowing/caring that it is a list or what T is: 您可以使用以下代码创建类型,然后dynamic类型可用于在不知道/关心它是列表或T是什么的情况下对List<T>的各种成员进行类型化

using System;
using System.Collections.Generic;

namespace ConsoleApplication61
{
    class Program
    {
        static void Main(string[] args)
        {
            dynamic o = CreateGeneric(typeof(List<>), typeof(int));
            o.Add(1);
            Console.WriteLine(o[0]);
            Console.Read();
        }

        public static object CreateGeneric(Type generic, Type innerType, params object[] args)
        {
            System.Type specificType = generic.MakeGenericType(new System.Type[] { innerType });
            return Activator.CreateInstance(specificType, args);
        }
    }
}

The above sample duck types the Add method and the Indexer. 上面的示例duck类型是Add方法和Indexer。 The DLR does the type handling and the duck typing at runtime - knowing that 1 is an int , for example. DLR在运行时执行类型处理和鸭子类型 - 例如,知道1int

Just to clarify, I likely wouldn't use such code in production (unless you requirements are very specific to need this) and any issues with type-mismatching will occur at run time; 只是为了澄清,我可能不会在生产中使用这样的代码(除非你的要求非常具体需要这个),并且任何类型不匹配的问题都会在运行时发生; so you either need to type very accurately (limited IntelliSense) or have good error handling. 因此您需要非常准确地键入(有限的IntelliSense)或具有良好的错误处理。

Thanks to this blog post for the CreateGeneric method. 感谢这篇关于CreateGeneric方法的博客文章

This assumes .NET 4 with the new CLR. 这假定.NET 4具有新的CLR。 As @MartinLiversage has also pointed out, this particular sample assumes that you are utilising the list in a sort-of-strongly-typed manner. 正如@MartinLiversage也指出的那样,这个特定的示例假设您以强类型的方式使用列表。 In my example I am passing an int to a List<int> hidden in a dynamic . 在我的例子中,我将一个int传递给dynamic隐藏的List<int>


We have been on .NET 4 almost since it was released. 自从它发布以来,我们一直在使用.NET 4。 We have a large application with an even larger code base. 我们有一个大型应用程序,具有更大的代码库。 dynamic isn't used once in the application, and only a few times in the test code base. dynamic在应用程序中不使用一次,在测试代码库中只使用几次。 That isn't to say "don't use it", it's to say "most of the time, you don't need it". 这并不是说“不要使用它”,而是说“大多数时候,你不需要它”。

You can do it like this: 你可以这样做:

foreach(Type t in classes)
{
   var listType = typeof(List<>).MakeGenericType(t);
   var instance = Activator.CreateInstance(listType);
}

This is possible with the Type.MakeGenericType Method 这可以使用Type.MakeGenericType方法

Here's a nifty method I found that should work for ya: CodeRef 这是一个我发现应该适用于ya的漂亮方法: CodeRef

public static object CreateGeneric(Type generic, Type innerType, params object[] args)
{
    System.Type specificType = generic.MakeGenericType(new System.Type[] { innerType });
    return Activator.CreateInstance(specificType, args);
}

And use it like so: 并像这样使用它:

var o = CreateGeneric(typeof(List<>), t);

Unfortunately, to add items you'll have to do it like so (where item is the item you're adding). 不幸的是,要添加项目,您必须这样做(其中item是您要添加的项目)。

MethodInfo addMethod = o.GetType().GetMethod("Add");
addMethod.Invoke(o, new object[] { item.ToType(t) });

Or use the Generic type as mentioned in another answer. 或者使用另一个答案中提到的Generic类型。

You can try this: 你可以试试这个:

Type[] classes = new Type[] { typeof(A), typeof(B) };           
foreach (Type t in classes)
{
     Type genericType = typeof(List<>).MakeGenericType(t);
     var list = Activator.CreateInstance(genericType);
}

If you want to keep to objects in one list then probably they have something in common. 如果你想在一个列表中保留对象,那么它们可能有一些共同之处。

In such case, I would argue that, just like LB mentioned in a comment, you are asking a wrong question here. 在这种情况下,我认为,就像评论中提到的LB一样,你在这里提出了一个错误的问题。

Probably it's a design issuethat you have. 可能这是你的设计问题。 Think about those types, see what they have in common and think about deriving from one base type or make both implement the same interface. 考虑一下这些类型,看看它们有什么共同点,并考虑从一种基本类型派生,或者两者都实现相同的接口。 In such case you would be able to instantiate a list of the objects of the base type/interface and work with those. 在这种情况下,您将能够实例化基本类型/接口的对象列表并使用它们。

Just to give you a head start: 只是为了给你一个良好的开端:

    abstract class Vehicle {
        public int NumberOfWheels { get; set; }
    }

    class Car : Vehicle
    {
        public Car()
        {
            NumberOfWheels = 4;
        }
    }

    class Bicycle : Vehicle
    {
        public Bicycle()
        {
            NumberOfWheels = 2;
        }
    }

    static void Main(string[] args)
    {

        var v1 = new Car();
        var v2 = new Bicycle();

        var list = new List<Vehicle>();
        list.Add(v1);
        list.Add(v2);

        foreach (var v in list)
        {
            Console.WriteLine(v.NumberOfWheels);
        }

        Console.ReadKey();
    }

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

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