【问题标题】:Purpose of Activator.CreateInstance with example?Activator.CreateInstance 的目的与示例?
【发布时间】:2011-09-29 13:32:42
【问题描述】:

谁能详细解释Activator.CreateInstance()的用途?

【问题讨论】:

标签: c# .net reflection


【解决方案1】:

假设您有一个名为 MyFancyObject 的类,如下所示:

class MyFancyObject
{
 public int A { get;set;}
}

它可以让你转动:

String ClassName = "MyFancyObject";

进入

MyFancyObject obj;

使用

obj = (MyFancyObject)Activator.CreateInstance("MyAssembly", ClassName))

然后可以执行以下操作:

obj.A = 100;

这就是它的目的。它还具有许多其他重载,例如提供Type 而不是字符串中的类名。为什么你会遇到这样的问题是另一回事。这里有一些需要它的人:

【讨论】:

  • 这对我很有用。就我而言,该类位于不同的命名空间中,因此我必须确保将命名空间包含在我的 ClassName 字符串中(即String ClassName = "My.Namespace.MyFancyObject";)。
  • 您忘记添加 Unwrap()。你也可以输入null,而不是“MyAssembly”,系统会搜索当前的Assembly。
  • 我可以做这样的事情吗obj = (MyFancyObject)Activator.CreateInstance("MyAssembly", ClassName)) 但不是使用类型进行转换。使用由 ClassName 制成的类型进行投射?喜欢这个Type type = Type.GetType(ClassName);obj = (type )Activator.CreateInstance("MyAssembly", ClassName)) ?
  • @Pan.student YES 了解更多信息,这是一个完美的教程视频,展示了使用泛型和委托的确切代码行。 JeremyBytes - C# Generics - Part 3: Methods & Delegates - You Tube
【解决方案2】:

我可以给你一个例子,为什么要使用这样的东西。设想一个游戏,您希望将关卡和敌人存储在 XML 文件中。当你解析这个文件时,你可能会有这样一个元素。

<Enemy X="10" Y="100" Type="MyGame.OrcGuard"/>

您现在可以做的是,动态创建关卡文件中的对象。

foreach(XmlNode node in doc)
   var enemy = Activator.CreateInstance(null, node.Attributes["Type"]);

这对于构建动态环境非常有用。当然,它也可以将其用于插件或插件场景等等。

【讨论】:

  • 我知道这是创建一个类型的新实例,但这是一个很好的简单示例,说明了为什么要这样做。
  • 你是说使用动态环境的好处是可以进行类多态(polymorphism-like)编程吗?
【解决方案3】:

我的好朋友 MSDN can explain it to you, with an example

以下是链接或内容将来更改的代码:

using System;

class DynamicInstanceList
{
    private static string instanceSpec = "System.EventArgs;System.Random;" +
        "System.Exception;System.Object;System.Version";

    public static void Main()
    {
        string[] instances = instanceSpec.Split(';');
        Array instlist = Array.CreateInstance(typeof(object), instances.Length);
        object item;
        for (int i = 0; i < instances.Length; i++)
        {
            // create the object from the specification string
            Console.WriteLine("Creating instance of: {0}", instances[i]);
            item = Activator.CreateInstance(Type.GetType(instances[i]));
            instlist.SetValue(item, i);
        }
        Console.WriteLine("\nObjects and their default values:\n");
        foreach (object o in instlist)
        {
            Console.WriteLine("Type:     {0}\nValue:    {1}\nHashCode: {2}\n",
                o.GetType().FullName, o.ToString(), o.GetHashCode());
        }
    }
}

// This program will display output similar to the following: 
// 
// Creating instance of: System.EventArgs 
// Creating instance of: System.Random 
// Creating instance of: System.Exception 
// Creating instance of: System.Object 
// Creating instance of: System.Version 
// 
// Objects and their default values: 
// 
// Type:     System.EventArgs 
// Value:    System.EventArgs 
// HashCode: 46104728 
// 
// Type:     System.Random 
// Value:    System.Random 
// HashCode: 12289376 
// 
// Type:     System.Exception 
// Value:    System.Exception: Exception of type 'System.Exception' was thrown. 
// HashCode: 55530882 
// 
// Type:     System.Object 
// Value:    System.Object 
// HashCode: 30015890 
// 
// Type:     System.Version 
// Value:    0.0 
// HashCode: 1048575

【讨论】:

  • 不太可能发生在 MSDN 中,复制这里的内容几乎侵犯了版权;)
  • 你是对的。就个人而言,我认为该原则也可以提供更好的答案。从我目前的项目中,我经常带着很多想法来到 SO。我通常只想要一个简单而中肯的答案,这样我就可以从中断的地方继续。我讨厌打开文章,有时甚至链接到其他文章。许多回答者没有意识到很多人没有时间来这里阅读几篇文章,还有大量不必要的介绍和谈话。简要总结一篇好文章的重要部分是我所见过的一些最佳答案的关键。
【解决方案4】:

你也可以这样做 -

var handle = Activator.CreateInstance("AssemblyName", 
                "Full name of the class including the namespace and class name");
var obj = handle.Unwrap();

【讨论】:

  • Unwrap() 是缺失的部分。 :)
  • 我找不到上面要使用的“Unwrap()”方法(如上)。新的 .NET API 有什么变化吗?
  • 它还在 System 命名空间中。
  • 您能否就.Unwrap() 的确切作用以及它与其他解决方案的关系提供一些额外的解释?
  • @Sam 它在 CreateInstance 的不同重载上,它返回 System.Runtime.Remoting.ObjectHandle
【解决方案5】:

下一个很好的例子是:例如,您有一组记录器,并且您允许用户通过配置文件指定要在运行时使用的类型。

然后:

string rawLoggerType = configurationService.GetLoggerType();
Type loggerType = Type.GetType(rawLoggerType);
ILogger logger = Activator.CreateInstance(loggerType.GetType()) as ILogger;

或者另一种情况是当您有一个公共实体工厂,它创建实体,并且还负责通过从数据库接收到的数据初始化实体:

(伪代码)

public TEntity CreateEntityFromDataRow<TEntity>(DataRow row)
 where TEntity : IDbEntity, class
{
   MethodInfo methodInfo = typeof(T).GetMethod("BuildFromDataRow");
   TEntity instance = Activator.CreateInstance(typeof(TEntity)) as TEntity;
   return methodInfo.Invoke(instance, new object[] { row } ) as TEntity;
}

【讨论】:

  • 这不起作用,typeof(loggerType) 导致loggerType is a variable and used like a type
【解决方案6】:

Activator.CreateInstance 方法使用与指定参数最匹配的构造函数创建指定类型的实例。

例如,假设您将类型名称作为字符串,并且您希望使用该字符串来创建该类型的实例。您可以为此使用Activator.CreateInstance

string objTypeName = "Foo";
Foo foo = (Foo)Activator.CreateInstance(Type.GetType(objTypeName));

这是一篇 MSDN 文章,更详细地解释了它的应用程序:

http://msdn.microsoft.com/en-us/library/wccyzw83.aspx

【讨论】:

  • 或者你可以使用new Foo()。我认为 OP 想要一个更现实的例子。
  • 我同意@Konrad。使用CreateInstance 的原因是如果您不知道要在设计时实例化的对象类型。在此示例中,您清楚地知道它的类型为 Foo,因为您将其转换为类型 Foo。你永远不会这样做,因为你可以这样做Foo foo = new Foo()
【解决方案7】:

在 deepee1 和 this 的基础上,以下是如何接受字符串中的类名,然后使用它通过 LINQ 读取和写入数据库。我使用“动态”而不是 deepee1 的强制转换,因为它允许我分配属性,这允许我们动态选择和操作我们想要的任何表。

Type tableType = Assembly.GetExecutingAssembly().GetType("NameSpace.TableName");
ITable itable = dbcontext.GetTable(tableType);

//prints contents of the table
foreach (object y in itable) {
    string value = (string)y.GetType().GetProperty("ColumnName").GetValue(y, null);
    Console.WriteLine(value);
}

//inserting into a table
dynamic tableClass = Activator.CreateInstance(tableType);
//Alternative to using tableType, using Tony's tips
dynamic tableClass = Activator.CreateInstance(null, "NameSpace.TableName").Unwrap();
tableClass.Word = userParameter;
itable.InsertOnSubmit(tableClass);
dbcontext.SubmitChanges();

//sql equivalent
dbcontext.ExecuteCommand("INSERT INTO [TableNme]([ColumnName]) VALUES ({0})", userParameter);

【讨论】:

    【解决方案8】:

    如果你已经知道这个类并且要转换它,你为什么要使用它? 为什么不只是用老式的方式来做,让课堂像你一直做的那样呢?与正常完成的方式相比,这没有任何优势。 有没有办法获取文本并对其进行操作:

    label1.txt = "Pizza" 
    Magic(label1.txt) p = new Magic(lablel1.txt)(arg1, arg2, arg3);
    p.method1();
    p.method2();
    

    如果我已经知道它是比萨饼,那么:

    p = (Pizza)somefancyjunk("Pizza"); over
    Pizza p = new Pizza();
    

    但如果存在的话,我认为 Magic 方法的巨大优势。

    【讨论】:

    • 也许this 会回答你的问题;)
    【解决方案9】:

    结合反射,我发现 Activator.CreateInstance 在将存储过程结果映射到the following answer 中描述的自定义类方面非常有帮助。

    【讨论】:

      【解决方案10】:

      我们用它来做类似的事情

      public interface IExample
      {
          void DoSomethingAmazing();
      }
      
      public class ExampleA : IExample
      {
          public void DoSomethingAmazing()
          {
              Console.WriteLine("AAAA");
          }
      
          public void DoA()
          {
              Console.WriteLine("A")
          }
      }
      
      public class ExampleB : IExample
      {
          public void DoSomethingAmazing()
          {
              Console.WriteLine("BBBB");
          }
      
          public void DoB()
          {
              Console.WriteLine("B")
          }
      }
      

      然后提供从设置文件序列化的类型

      => 即使在编译之后,我们仍然可以通过使用不同的设置来改变应用程序的行为

      类似的东西,例如

      public static class Programm
      {
          public static void Main()
          {
              var type = MagicMethodThatReadsASerializedTypeFromTheSettings();
              var example = (IExample) Activator.CreateInstance(type);
      
              example.DoSomethingAmazing();
      
              switch(example)
              {
                  case ExampleA a:
                      a.DoA();
                      break;
      
                  case ExampleB b:
                      b.DoB();
                      break;
              }
          }
      }
      

      我在一个自定义的多用户序列化中使用它,我将 RPC(远程过程调用)发送到带有参数的其他设备。

      它基本上做到了必要的裁剪

      public ISendable
      {
          public byte[] ToBytes();
          public void FromBytes(byte[] bytes);
      }
      
      // Converts any ISendable into a byte[] with the content
      // typeBytes + contentBytes
      public byte[] ToBytes(ISendable toSend)
      {
          var typeBytes = Encoding.ASCII.GetBytes(toSend.GetType().AssemblyQualifiedName);
          var contentBytes = ISendable.ToBytes();
      
          return MagicMethodToCombineByteArrays(typeBytes, contentBytes);
      }
      
      // Coonverts back from byte[] to the according ISendable
      // by first reading the type, creating the instance and filling it with
      // contentBytes
      public T FromBytes<T>(byte[] bytes) where T : ISendable
      {
          MagicMethodToSplitInputBytes(out var typeBytes, out var contentBytes);
          var type = Encoding.ASCII.GetString(typeBytes);
      
          var instance = (T) Activator.CreateInstance(type);
          instance.FromBytes(contentBytes);
      
          return instance;
      }
      

      【讨论】:

        猜你喜欢
        • 2013-12-28
        • 1970-01-01
        • 2021-11-13
        • 1970-01-01
        • 2021-09-18
        • 2023-03-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多