【问题标题】:How do I create a generic class from a string in C#? [duplicate]如何从 C# 中的字符串创建泛型类? [复制]
【发布时间】:2009-03-26 20:04:31
【问题描述】:

我有一个这样的通用类:

public class Repository<T> {...}

我需要用一个字符串来实例化它...... 示例:

string _sample = "TypeRepository";
var _rep = new Repository<sample>();

我该怎么做?这可能吗?

谢谢!

【问题讨论】:

  • 请注意,您不能在程序中引用 Repository,因此 _rep 的类型必须是 object 或所有 Repository 的通用接口。

标签: c# .net reflection generics


【解决方案1】:

这是我的 2 美分:

Type genericType = typeof(Repository<>);
Type[] typeArgs = { Type.GetType("TypeRepository") };
Type repositoryType = genericType.MakeGenericType(typeArgs);

object repository = Activator.CreateInstance(repositoryType);

在评论中回答问题。

MethodInfo genericMethod = repositoryType.GetMethod("GetMeSomething");
MethidInfo closedMethod = genericMethod.MakeGenericMethod(typeof(Something));
closedMethod.Invoke(repository, new[] { "Query String" });

【讨论】:

  • 我如何访问存储库方法?
  • 使用反射为仅在运行时知道的类型创建存储库的方式相同。您需要灵活性,您需要为此付费。
  • 你能告诉我怎么做吗?谢谢!
  • 不客气,很高兴我能提供帮助。
【解决方案2】:

首先使用Type.GetType(stringContainingTheGenericTypeArgument)获取Type对象

然后使用typeof(Repository&lt;&gt;).MakeGenericType(theTypeObject) 获取泛型类型。

最后使用Activator.CreateInstance

【讨论】:

  • 真正的问题不是“他应该”吗?
  • 从字符串到泛型?可能。但是 MakeGenericType 经常用于 linq 提供程序,例如其他表达式树消费代码。它是一个很好的帮手,尽管对于日常的 LOB 应用程序来说,当然不用担心。
【解决方案3】:

这是 C# 4.0 中 dynamic 关键字的工作。

这里有一些不错的技巧可以为您提供对象的实例,但不管当前版本的 C# 是什么,它只会知道它有一个 object,而且它本身不能对对象做太多事情因为当前的 C# 不支持后期绑定。您至少需要能够将其转换为已知类型才能对其进行任何操作。最终,您必须在编译时知道您需要的类型,否则您就不走运了。

现在,如果您可以将存储库类限制为实现某个已知接口的类型,那么您的状态会好很多。

【讨论】:

  • 所以,我的问题没有解决方案...
  • 不,我的意思是,除非您重新考虑您的架构,否则在 C# 4 出现之前您将无法获得真正有效的解决方案。
  • 如果您分享您打算如何处理这些存储库对象,我们或许可以帮助您设计出更好的设计。
【解决方案4】:

如果我正确理解了您的问题...您要做的是采用您的类型 (Repository) 并在运行时构造一个特定的通用实现?

如果是这样,请查看MakeGenericType。您可以使用 typeof(Repository) 和您想要的 T 对象的 System.Type 并以这种方式构造它。一旦你有了类型,Activator.CreateInstance 就会为你工作。

【讨论】:

    【解决方案5】:

    假设你的字符串包含一个类型的名字,你可以这样写

    object _rep = Activator.CreateInstance(typeof(Repository<>).MakeGenericType(Type.GetType(_sample)));
    

    但是,_rep 将是一个无类型的对象,您将无法对它做任何事情。由于您在编译时不知道泛型类是什么类型,因此没有将其转换为的类型。 (除非 Repository 继承了非泛型类或实现了非泛型接口)

    您可以通过为 Repository 创建一个非泛型基类并将对象转换为它来解决这个问题。

    但是,根据您的情况,您可能希望将 Repository 设为非泛型类。

    如果Repository 是一个包含其他类的类,最好将其设为非泛型。你可以让它的构造函数接受一个Type 对象,然后在你添加的每个对象上调用Type.IsInstanceOfType 以确保它是正确的类型。

    如果 Repository 是事物的分类集合,最好将其设为非泛型,并使其构造函数采用 string category

    如果您需要更具体的建议,请发布有关您情况的更多详细信息。

    【讨论】:

    • 我的存储库:public class Repository : RepositoryWithTypedId, IRepository { } public class RepositoryWithTypedId : IRepositoryWithTypedId 我可以t改变那个实现......所以这是不可能的吗?
    • 这是可能的,使用我上面写的那行代码,但是做任何事情都非常困难。你为什么要这样做,你在用_rep做什么?
    • 我的 _rep 是一个 DAO(数据访问对象)...
    • 但是为什么编译时不知道类型名呢?您可能希望使包含 _rep 的整个类或方法通用
    • 我正在使用一个组件,我可以在其中为每个元素(我的组件)设置存储库类的名称。这是一个带有单选按钮的树视图......所以我得到了选定的收音机(和类名),我必须得到存储库......
    【解决方案6】:
    Type repType = typeof(Repository <>).MakeGenericType(Type.GetType("System.String"));
    object rep = Assembly.GetAssembly(repType).CreateInstance(repType.FullName);
    

    这将创建一个Repository&lt;string&gt; 的实例。您可以将“System.String”替换为您喜欢的任何类型。

    【讨论】:

      【解决方案7】:

      泛型适用于类型,而不适用于实例。你可以阅读更多here

      听起来你只需要向你的类添加一个构造函数,它接受所需的类型并初始化值:

      public class Foo<T>
      {
          private T = default(T);
      
          public Foo(T initValue)
          {
              _val = T;
          }
      }
      

      【讨论】:

        【解决方案8】:

        这是“有点”可能的。在某种程度上你可以做到,但它有点像 hack。

        您有 3 个选项:

        如果您事先了解自己的类,请使用 switch 语句。基本上是这样的:

        switch(str){
           case "TypeRepository": return new Repository<TypeRepository>;
        }
        

        作为上述更高级的形式,您可以使用字典而不是哈希表

        var factory = new Dictionary<string, Func<object>>();
        factory.Add( "TypeRepository", () => new Repository<TypeRepository>() );
        
        var theObject = factory["TypeRepository"]() as Repository<TypeRepository>;
        

        为了获得最大的灵活性,您可以在运行时使用反射将字符串与类匹配。请注意,反射是相当缓慢的,所以如果你有规律地这样做,你要避免它。例如,这里使用Frans Bouma's 方法。只需在您的代码中将List&lt;&gt; 更改为Repository&lt;&gt;

        public static object MakeList( string typeStr )
        {
            var nameSpace = "MyTestApplication" + ".";
        
            var objType = Type.GetType(nameSpace + typeStr); // NAMESPACE IS REQUIRED
            var listType = typeof(List<>).MakeGenericType(objType);
            return Activator.CreateInstance(listType);
        }
        
        var listOfThings = MakeList("MyCoolObject") as List<MyCoolObject>;
        

        注意:无法避免所有这些机制都返回 object 的事实,然后您必须将其转换为正确的类型,而不是只返回强类型的值。

        这是不可避免的,因为直到运行时您才知道列表的类型,而 C# 是围绕在编译时了解事物而构建的(这就是人们所说的“静态类型编程语言”的意思)。在 C#4 中这将不那么痛苦,您可以在其中返回 dynamic,这将节省您的演员表。

        【讨论】:

        • 鉴于该类型是使用字符串构造的,C# 如何合理地将特定类型与结果相关联?
        【解决方案9】:

        Generic 类中的“T”代表类型,而不是类型的实例。因此,如果您希望存储库保存字符串对象,请使用

        var _rep = new Repository<string>();
        

        【讨论】:

        • 我认为您误解了这个问题 - 字符串包含类型名称。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-06-17
        • 1970-01-01
        • 2011-08-08
        • 1970-01-01
        • 2021-09-23
        • 2020-09-17
        • 1970-01-01
        相关资源
        最近更新 更多