web-dev-qa-db-ja.com

例のあるActivator.CreateInstanceの目的は?

誰かがActivator.CreateInstance()目的を詳細に説明できますか?

107
Tabriz Atayi

次のようなMyFancyObjectというクラスがあるとします:

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

次のことができます。

String ClassName = "MyFancyObject";

MyFancyObject obj;

を使用して

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

そして、次のようなことができます:

obj.A = 100;

それがその目的です。また、文字列のクラス名の代わりにTypeを提供するなど、他の多くのオーバーロードがあります。なぜあなたがそのような問題を抱えるのかは別の話です。必要な人は次のとおりです。

135
deepee1

まあ、私はあなたにそのようなものを使用する理由の例を与えることができます。レベルと敵をXMLファイルに保存するゲームを考えてください。このファイルを解析すると、次のような要素がある場合があります。

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

ここでできることは、レベルファイルにあるオブジェクトを動的に作成することです。

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

これは、動的な環境を構築するのに非常に便利です。もちろん、これをプラグインまたはアドインのシナリオに使用することもできます。

44
dowhilefor

私の良き友人MSDN 例を使って説明できます

リンクまたはコンテンツが将来変更される場合のコードは次のとおりです。

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
12

これもできます-

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

次に良い例があります。たとえば、ロガーのセットがあり、ユーザーが構成ファイルを介してランタイムで使用されるタイプを指定できるようにします。

次に:

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

または、エンティティを作成する共通エンティティファクトリがあり、DBから受信したデータによるエンティティの初期化も担当している場合です。

(擬似コード)

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;
}
8
sll

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

2
James Johnson

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);
1
DharmaTurtle

すでにクラスを知っていて、それをキャストしようとしているのに、なぜそれを使用するのでしょうか?昔ながらのやり方で、いつものようにクラスを作ってみませんか?通常の方法よりも利点はありません。このようにテキストを取得して操作する方法はありますか?

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の方法が存在する場合、その方法には大きな利点があります。

0
user8659016

リフレクションと組み合わせて、Activator.CreateInstanceは、ストアドプロシージャの結果を 次の回答 で説明されているカスタムクラスにマッピングするのに非常に役立つことがわかりました。

0
usefulBee