如何创建动态类型的 List<T>?

17

我不希望我的列表是固定类型的。相反,我希望列表的创建取决于变量的类型。以下代码不起作用:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.Generic;
namespace ConsoleApplication3
{
    class Program
    {
        static void Main(string[] args)
        {

            string something = "Apple";

            Type type = something.GetType();

            List<type> list = null;

            Console.ReadKey();

        }
    }
}

有人能告诉我需要做哪些修改才能让它正常工作吗?我希望list的创建取决于something变量的类型。


3
你需要使用反射来完成这个任务。你不能使用静态类型变量。否则需要寻找不同的方法。 - David Heffernan
“我想要类型安全,但我需要动态类型安全。”你能详细说明一下吗? - David Heffernan
@David:动态类型安全是指,如果变量something的类型为int,则列表应该是int类型;如果它的类型为string,则列表应该是string类型,依此类推。 - Jaggu
1
@Jaggu 我不明白那是什么意思。你说的似乎并不涉及类型安全。你是在寻找在将错误类型的项添加到列表时出现运行时错误吗?这是你的意思吗? - David Heffernan
@David:是的,在这种情况下,运行时错误就足够了。如果没有编译错误也没关系。 - Jaggu
4个回答

54
string something = "Apple";
Type type = something.GetType();
Type listType = typeof(List<>).MakeGenericType(new [] { type } );
IList list = (IList)Activator.CreateInstance(listType);

这是创建静态未知类型列表的方法。但需要注意的是,您无法在静态上下文中指定列表的运行时类型,必须使用非泛型类型或甚至对象。

如果没有更多关于您想要实现的内容的信息,那么这就是您能做到的最好的。


1
酷!除了ver需要var。 - Jaggu
3
不,var不能完全做到你想要的。它不会给你一个类型为List<Apple>的变量,因为var是一种静态类型构造。 - David Heffernan
这会在列表操作中执行运行时类型检查吗?因此,如果您尝试添加不属于Apple类型的内容,是否会发生运行时错误? - David Heffernan
是的,绝对没问题。这是一个完全工作的通用列表实例。C#不像Java那样进行类型擦除。 - usr
谢谢你的教导。我猜@Jaggu所说的动态类型安全就是这些运行时检查。 - David Heffernan

6
我希望能够保证类型安全,但我需要动态类型安全。
如果您指的是运行时类型安全性,您可以使用反射创建 List<T>(请参见usr的回答)或 dynamic,然后将其视为非泛型的 IList
使用 dynamic,代码可能如下所示:
static List<T> CreateListByExample<T>(T obj)
{
    return new List<T>();
}

…

object something = "Apple";

IList list = CreateListByExample((dynamic)something);

list.Add(something); // OK

list.Add(42);        // throws ArgumentException

1
动态和反射都能正常工作,但性能会有所下降,并且会失去强类型、代码设计和清晰度等方面的优势。换句话说,如果可能的话,你应该始终尝试在不使用它的情况下解决问题——只要你的代码允许。因此,根据你具体的需求(非常重要),你也可以使用一个“技巧”来“推断”类型并使其通用化...
class Program
{
    static void Main(string[] args)
    {
        string something = "Apple";
        int test = 5;
        var list = something.GetList();
        var listint = test.GetList();
        Console.WriteLine(list.GetType());
    }
}
static class Extension
{
    public static List<T> GetList<T>(this T value)
    {
        return new[] { value }.ToList();
    }
}

...即使您在变量具有值并且在“进入”通用上下文之前,
您可以使用扩展(这对于周围非常有帮助), 并让它为您推断类型和列表类型
注意:这种“解决方法”不幸的是并不总是奏效,当您的代码过于动态时(我知道这不太“精确”,但超出了本文的范围),如果它依赖于反射引起的类型等。
即没有一个清晰的解决方案,这只是一个例子,您需要付出一些汗水:)使其适合您的工作-例如,您可能需要在此处和那里使用包装器类型,显然以这种方式创建列表可能不是您想要的。


-3
编译器必须在编译时知道泛型类型T。所以,不,你真的做不到这一点。

不需要在编译时知道T的类型。 - Asiri Dissanayaka

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接