例のActivator.CreateInstanceの目的?


124

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


6
おそらく、より大きなドキュメントと例は、一般的なオーバーロードでは利用できません。のドキュメントをオーバーロードCreateInstance(Type type)と一致させることをお勧めしCreateInstance<T>()ます。
ヨルゲンセンクラウス

4
MSDNページには、「ローカルまたはリモートでオブジェクトのタイプを作成するメソッド、または既存のリモートオブジェクトへの参照を取得するメソッドが含まれています。このクラスは継承できません。」という説明行が1つだけあります。msdn.microsoft.com/en-us/library/system.activator.aspx
gonzobrains

2
Javaのバックグラウンドからここに来た場合は、これがc#.net方法ですObject xyz = Class.forName(className).newInstance();
SNag

ここにはより良いドキュメントがあります
jpaugh

回答:


149

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

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

次のことが可能になります。

String ClassName = "MyFancyObject";

MyFancyObject obj;

使用する

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

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

obj.A = 100;

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


2
これは私にとって役に立ちました。私の場合、クラスは別の名前空間にあったので、ClassName文字列(つまりString ClassName = "My.Namespace.MyFancyObject";)に名前空間を含めたことを確認する必要がありました。
スコット

1
Unwrap()を追加するのを忘れました。「MyAssembly」の代わりにnullを指定することもでき、システムは現在のアセンブリを検索します。
トニー

1
obj = (MyFancyObject)Activator.CreateInstance("MyAssembly", ClassName))タイプでキャストする代わりに、このようなことはできますか?ClassNameから作成された型でキャストしますか?このようにType type = Type.GetType(ClassName);obj = (type )Activator.CreateInstance("MyAssembly", ClassName))
ルーク、2015年

1
上記とMyFancyObject obj = new MyFancyObjectはどう違いますか?
Ed Landau

1
@Ed Landau違いは、コンパイル時に型がわからない実行時にオブジェクトをインスタンス化できることです。たとえば、プログラムのプラグインシステムを構築している場合です。回答のリンクから、MyFancyObject obj = new MyFancyObject()と書くだけでは不可能な場合のアイデアが得られます。これはしばしば、一般的にリフレクションの使用と組み合わされます。また、stackoverflow.com / questions / 9409293 /…で、別の説明を確認することもできます。
deepee1 2016

47

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

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

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

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

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


5
型の新しいインスタンスを作成することだと理解しましたが、これは、なぜそうしたいのかを示す簡単でわかりやすい例です。
jamiebarrow

14

私の親友の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

1
MSDNで発生する可能性は低く、ここにコンテンツをコピーすることは、ほぼ著作権違反です;)
クラウスヨルゲンセン2013年

13
あなたが正しい。個人的には、原則はより良い答えを出すためにも機能すると感じています。私は現在のプロジェクトから多くのことを頭に入れてSOに来ることがよくあります。私は通常、単純で的確な回答を求めているので、中断したところから続行できます。私は時々他の記事にリンクしている記事を開かなければならないのが嫌いです。多くの回答者は、多くの人々が時間のないままここに来て、無数の不必要な紹介や講演を行って、いくつかの記事を読んでいないことを理解していません。良い記事の重要な部分を簡潔に要約することは、私が見た中で最高の答えのいくつかの鍵です。
Aske B. 2013

10

これを行うこともできます-

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

Unwrap()は欠けていた部分でした。:)
Tony

上記の 'Unwrap()'メソッドが見つかりません。新しい.NET APIで何か変更はありますか?
サム

それはまだシステム名前空間にあります。
ウィリアム

2
.Unwrap()正確には何が行われ、これが他のソリューションとどのように関連するかについて、追加の説明を提供できますか?
Jeroen Vannevel

@サムそれCreateInstanceが返す場所の異なるオーバーロードにありますSystem.Runtime.Remoting.ObjectHandle
nawfal

9

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

次に:

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

これは機能しません。typeof(loggerType)結果はloggerType is a variable and used like a type
Barkermn01

3

この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


5
または、単に使用することもできますnew Foo()。OPはより現実的な例を望んでいたと思います。
Konrad Rudolph

1
@Konradに同意します。使用する理由はCreateInstance、設計時にインスタンス化するオブジェクトのタイプがわからない場合です。この例では、type Fooとしてキャストしているので、それがtype であることは明らかですFoo。あなたはただできるので、あなたはこれを決してすることはないでしょうFoo foo = new Foo()
theyetiman 2013

1

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

0

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

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();

しかし、マジックの方法が存在すれば、それが非常に有利だと思います。


0

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.