【问题标题】:generic class, how to set the type in runtime?泛型类,如何在运行时设置类型?
【发布时间】:2012-06-10 14:53:01
【问题描述】:

我创建了一个泛型类,但我知道运行时的类型,而不是设计,所以我想知道如何在运行时设置类型。

例如,我有:

public class MyGenericClass<T>
{
....
}

然后我尝试使用它。我在其他类中有一个方法,它使用这个泛型类。在这个类的构造函数中,我接收到我想要的类型作为参数,所以我有一个类型属性,我在其中保存了我需要的类型。所以我正在尝试这个:

MyGenericClass<_typeNeeded> myClass = new MyGenericClass<typeNeeded>();

但这不起作用。

如何在我创建的类中设置运行时类型?

我正在使用 C# 4.0。

谢谢。 戴姆洛克。

编辑:我想要做的是以下。我有一个类需要对数据库进行一些查询。这个查询总是返回相同的信息,一个类,但是包含这个类的信息来自不同的表。这是因为我需要确定要使用的查询。为了决定使用什么查询,我使用收到的类型。

是因为这个原因我在设计时不知道类型,而是在运行时。

我可以使用将由类实现的接口,并使用用正确的类实例化的接口,但这使我在实例化的时刻有一个开关或一个 if,这就是我尽量避免,我想要更通用的东西。另外,如果我使用这个解决方案,在实例化的那一刻有一个 if,我可以创建泛型类,所以我只有一个类,它会更易于维护。

【问题讨论】:

  • 如果没有广泛的反思,这是不可能的。
  • 你见过this link吗?
  • 为什么不用动态关键字?
  • 你能说得更具体一点吗?你想达到什么结果?
  • @Mark M:在这个例子中,我如何使用该方法?因为该方法返回一个对象,但我必须首先声明变量 MyGenericClass miVariable = CreateGeneric...) 但问题是我不知道 T 的类型。但是该示例喜欢我正在寻找的为。

标签: c# generics runtime generic-programming


【解决方案1】:

看看MakeGenericType 方法。您可以使用它来创建一个 Type 实例(然后可用于创建该类型的实例),并在运行时确定通用参数值。但是请注意,在处理该对象的通用特征时,您将需要更多的反思;您不能在代码中创建类型为带有变量类型参数的泛型类型的变量。

【讨论】:

    【解决方案2】:

    您可以通过另一种方式创建您的类,将您想要使用的类型传递给构造函数并利用dynamic 关键字。

    例如:

    class MyGeneralClass
    {
        dynamic myVariable;
        Type type;
    
        public MyGeneralClass(Type type)
        {  
            this.type = type;
            myVariable = Activator.CreateInstance(type);
            //And then if your type is of a class you can use its methods      
            //e.g. myVariable.MyMethod();
        }
    
        //If your function return something of type you can also use dynamic
        public dynamic Function()
        {
            return Activator.CreateInstance(type);
        }
    }
    

    【讨论】:

      【解决方案3】:

      如果您考虑一下,没有理由拥有在运行时确定类型的泛型。泛型提供强类型,但这只有在编译时知道类型时才有可能。这是泛型最大的好处之一,它提供了安全性,因为您知道对象可以执行哪些操作。在运行时,如果你不知道你得到的是什么类型,那将违背这个目的,你将不得不深入研究 reflection 的强大(但有时是危险的)世界。例如,

      List<DateTime> list = new List<DateTime>();
      foreach (DateTime item in list)
         item.Minute + ": " + item.Hour
      

      因为我在编译时知道类型,所以我可以将它存储在一个通用容器中,并且在使用它时我具有类型安全性。我知道该项目具有 Minute 和 Hour 属性。


      如果要根据对象的类型执行操作,则使用 GetType() 方法。这是您进入运行时类型识别和处理的窗口。

      Result PerformQuery(object unknownObject)
      {
          switch (object.GetType())
          {
               case typeof(ThisType): Do This; break;
               case typeof(ThatType): Do That; break;
          }
      }
      

      如果您要对对象做某事,那么您要么在编译时知道方法名称,这意味着您可以使用接口,

      IFood hamburger = new Hamburger();
      hamburger.BeEaten();
      

      如果您没有或想要使用接口,您可以使用反射或动态,在这种情况下,如果我知道要调用什么方法,我会使用动态。

      Result PerformQuery(object unknownObject)
      {
          if (object.GetType() == typeof(Pizza))  
          {
              dynamic pizza = unknownObject;
              pizza.BakeInOven() // since I checked and know it is type Pizza it is 'somewhat' safe to do this, unless Pizza class changes the name of BakeInOven method.
           }
       }
      

      最后,如果您不知道要在编译时调用的方法,您可以使用反射。

        string methodName = CalculateWhatMethodShouldBe();
        MethodInfo myMethod = unknownObject.GetType().GetMethods().First(m => m.Name == methodName);    
        MethodInfo.Invoke(unknownObject);
      

      【讨论】:

        【解决方案4】:

        我没有关于你的代码的足够信息,但也许你可以使用简单的多态性:

        public interface IMyInterface
        {
        ...
        }
        
        public class MyGenericClass<T> : IMyInterface
        {
        ....
        }
        
        IMyInterface myClass = new MyGenericClass<typeNeeded>();
        

        您也可以将其与工厂设计模式混合使用,以便其他一些类将根据一些运行时知识负责您的类型的实例化。

        这当然假设您的 MyGenericClass 没有类似的方法:

        public T GetT(){...}
        

        或者如果它确实存在所有 T'types 之间的附加关系,因此它们都有共同的超类,比如说 BaseT,你可以更改

        public T GetT(){...}
        

        到:

        public BaseT GetT(){...}
        

        【讨论】:

        • typeNeeded 是 OP 问题中的一个变量,所以 new MyGenericClassy&lt;typeNeeded&gt;() 不会编译。
        • 好的,好点。无论如何,如果我们知道 T 不是任何类型,而是我们知道的少数类型之一,并且我们需要简单快速的解决方案(没有反射),那么我们可以使用带有 switch 语句的工厂进行类型实例化并坚持这个解决方案。
        • 是的。让我们看看 OP 是否想走这条路并需要更多信息。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2023-03-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-06-30
        相关资源
        最近更新 更多