创建一个取决于字符串值的类型列表

Create a List of type which depends on a string value

假设我有一个 .txt 文件,其中:

  1. 第一个词是 class 的类型或名称(即使是用户定义的 class)。所以编译器可以接受任何东西。
  2. 以下单词是该类型的值。

举个例子:

int 1 2 3 5 6 8 19 20

如何在 C# 中创建第一个单词类型的列表?这种东西明明是违法的,但为了说清楚我的需要我还是写出来:

static void Main(string[] args)
        {
            System.IO.StreamReader file = 
            new System.IO.StreamReader(@"c:\test.txt");
            string[] words = reader.ReadToEnd().Split(' ');
            List<words[0]> list = new List<words[0]>;
        }

即使那是可能的,操作 list.add(word[i]) 也应该是一个问题(因为每个元素也是一个字符串)!

重要提示:项目细节中不允许反射,因为性能很差!

如果不涉及某种方式的运行时反射,您就无法在 C# 中执行此操作。

也许最实用的方法来做一些接近你所要求的事情,并且没有明确涉及反射是使用 dynamic:

var t = typeof(int); // or some other type based on the input
dynamic list = Activator.CreateInstance(typeof(List<>).MakeGenericType(t));

然后您可以简单地使用 list.Add(x),其中 x 是适当类型的值——但您还必须以某种方式将输入转换为该类型——您不能只添加您从文件中读取的字符串。

后者是一个可能比创建和使用列表本身更难解决的问题:如何将字符串(这是您总是从文件中读取的内容)转换为由指定的某种任意类型的值用户?

强烈建议不要尝试这样做,至少在您提出的完全不受约束的要求下。

至少有几个小的、可解决的问题:

  1. 需要反思,尽管你很想避免。没有任何实用的方法可以在不进行反射的情况下将包含类型名称的简单字符串转换为您正在寻找的数据结构。您可以通过使用 "memoization" 模式(即缓存每个类型的反序列化对象,以避免对每一行输入进行反射的开销)以及使用 Expressions 来最小化性能问题构建缓存的反序列化对象(这将确保在实际处理数据时获得最佳性能)。
  2. 没有通用的方法来解析字符串值以创建某种任意类型的实例。您可以通过检查类型本身以获取可用于完成任务的某种方法来部分解决此问题。例如。使用反射查找名为 "Parse" 的方法,并使用该方法将字符串转换为类型实例。但显然这不适用于缺少这种方法的类型;这不可调和地阻止了字面上处理 any 可能类型的可能性。

还有一些更重要的问题(即极难或不可能解决):

  1. 您的示例甚至无法运行,因为 int 不是实际的 .NET 类型名称。您必须使用特殊情况的 C# 类型别名,如 intboollong 等才能使其正常工作。
  2. 即使使用反射(这是正确的方法),您仍然需要完全限定的类型名称来可靠地处理这个问题。例如,执行中的 AppDomain 完全有可能具有多个名为 Point 的类型。没有名字space,就无法有效解决歧义
  3. 给定一个完全限定的类型名称,.NET 默认情况下将只搜索正在执行的程序集和 mscorlib.dll 给定类型。如果您想在其他程序集中查找类型,则必须自己进行搜索。显然,您最多只能处理 AppDomain 的入口点程序集引用的程序集中包含的类型。要处理间接引用的程序集,您需要递归地搜索程序集类型以找到您要查找的类型名称。显然,无法处理未知程序集中的类型。
  4. 从您的问题中完全不清楚您希望如何使用这些对象的这个通用列表。使用泛型非常好,例如以确保类型安全。但是,如果您实际上不能为所读取的特定类型声明一个实际上属于 List<T> 类型的变量,那么对某些特定类型使用 List<T> 通常会非常不方便。
  5. 可能最大的问题之一是并非所有类型都可以表示为 space 分隔值!例如,如果类型名称是 System.String,您希望输入文本看起来像什么。如果任何字符串值本身有一个 space,那将被误认为是值分隔符,在解析时破坏数据。

上面的一些问题可以通过约束问题来解决。例如,要求每个类型都实现一个静态 Parse() 方法,要求每个类型都被进程中的一个程序集引用,限制该类型的可能值,或者提供用于分隔或格式化值的附加规则在文本等中。但只有当您愿意放弃您在问题中规定的原始、广泛的规范时,这些才有效。

理想情况下,您只需提前知道可能需要解析哪些类型,然后为每种类型编写特定的代码。这是最可靠的,尽管更耗时。

此主题的一个变体可能适用于您的场景,即使用 Managed Extensibility Framework (MEF)(或类似技术)提供加载项机制,其中提供特定于类型的加载项知道如何解析一行输入。每个加载项都会发布一个名称(不需要是实际的真实类型名称......它只需要是唯一的),然后您的程序将检索适当的加载项以根据在该行的开头(如您的示例所示)。

底线:如前所述,从字面上看规范,这是无法以任何合理的方式完成的。

您将不得不至少在一定程度上限制要求的范围,以促进实际的解决方案。如果您实际上限制了您的要求范围,我已经在上面提供了一些关于它如何工作的一般指导。如果您不知道如何去做,请随时提出关于问题的各个部分的新问题。