创建一个依赖于字符串值的类型列表

时间:2015-01-17 19:37:09

标签: c# generics

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

  1. 第一个单词是类的类型或名称(甚至是用户定义的类)。所以它可能是编译器接受的任何东西。
  2. 以下字词是该类型的值。
  3. 举个例子:

    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])应该是一个问题(因为每个元素也是一个字符串)!

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

2 个答案:

答案 0 :(得分:2)

你不能在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 :(得分:0)

我会强烈建议不要尝试这样做,至少在你已经说过完全不受约束的要求时。

至少有一些轻微的,可解决的问题:

  1. 尽管你想避免它,但仍需要反思。没有实际的方法可以将包含类型名称的简单字符串转换为您无需反思即可查找的数据结构。您可以使用&#34; memoization&#34;最小化性能问题。模式(即缓存每个类型的反序列化对象,以避免每个输入行经过反射的开销),以及使用Expression来构建缓存的反序列化对象(这将确保最佳性能)实际处理数据时。)
  2. 没有通用的方法来解析字符串值以创建某种任意类型的实例。您可以通过检查类型本身以获取可用于完成任务的某些方法来部分解决此问题。例如。使用反射来查找名为&#34; Parse&#34;的方法,并使用该方法将字符串转换为类型实例。但显然这对于​​缺少这种方法的类型不起作用;这不可调和地阻止了字面处理任何可能类型的可能性。
  3. 还有一些更为重要的问题(即极难或无法解决):

    1. 您的示例甚至无法正常工作,因为int不是实际的.NET类型名称。您需要使用特殊情况下的C#类型别名,例如intboollong等,才能实现这一点。
    2. 即使使用反射(这是正确的方法),您仍然需要完全限定的类型名称来可靠地处理此问题。例如,执行AppDomain有多个名为Point的类型,这是完全可能的。没有命名空间,就无法有效解决歧义。
    3. 给定一个完全限定的类型名称,.NET默认只搜索执行程序集和mscorlib.dll给定的类型。如果要在其他程序集中查找类型,则必须自己进行搜索。显然,您只能处理AppDomain入口点程序集引用的程序集中包含的类型。要处理间接引用的程序集,您需要递归搜索程序集类型以查找您正在查找的类型名称。显然,无法处理未知程序集中的类型。
    4. 您的问题根本不清楚如何使用这些对象的通用列表。使用仿制药很好,例如确保类型安全。但是,如果您实际上无法为已读取的特定类型声明List<T>类型的变量,那么对某些特定类型使用List<T>通常会非常不方便。< / LI>
    5. 可能最大的问题之一是并非所有类型都可以表示为以空格分隔的值!例如,考虑一下如果类型名称为System.String,您希望输入文本的外观。如果任何字符串值本身都有空格,那么它将被误认为是值分隔符,在解析数据时会破坏它。
    6. 通过约束问题可以解决上述一些问题。例如,要求每种类型实现静态Parse()方法,要求每个类型由进程中的一个程序集引用,限制类型的可能值,或提供用于分隔或以其他方式格式化值的其他规则在文中等等。但这些只有在您愿意退出您在问题中规定的原始广泛规范时才有效。

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

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

      底线:如上所述,按照字面意思采用规范,这不能以任何合理的方式完成。

      您必须至少在某种程度上限制要求的范围,以促进实际的解决方案。如果你确实限制了你的要求范围,我已经提供了一些关于如何工作的一般指导。如果您无法确定如何解决问题,请随时询问有关问题各个部分的新问题。