Tujuan Activator.CreateInstance dengan contoh?

124

Bisakah seseorang menjelaskan Activator.CreateInstance()tujuan secara rinci?

Tabriz Atayi
sumber
6
Mungkin dokumentasi dan contoh yang lebih besar tidak tersedia dalam overload generik. Saya akan mendorong bahwa dokumentasi dari CreateInstance(Type type)cocok dengan CreateInstance<T>()kelebihan beban.
Claus Jørgensen
4
Halaman MSDN hanya memiliki satu baris penjelasan, "Berisi metode untuk membuat jenis objek secara lokal atau jarak jauh, atau mendapatkan referensi ke objek jarak jauh yang ada. Kelas ini tidak dapat diwariskan." msdn.microsoft.com/en-us/library/system.activator.aspx
gonzobrains
2
Jika Anda datang ke sini dari latar belakang Java, inilah c#.netcara melakukannya Object xyz = Class.forName(className).newInstance();.
SNag
Ada dokumentasi yang lebih baik untuk itu di sini .
jpaugh

Jawaban:

149

Katakanlah Anda memiliki kelas yang disebut MyFancyObjectseperti ini di bawah ini:

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

Ini memungkinkan Anda mengubah:

String ClassName = "MyFancyObject";

Ke

MyFancyObject obj;

Menggunakan

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

dan kemudian dapat melakukan hal-hal seperti:

obj.A = 100;

Itulah tujuannya. Ini juga memiliki banyak kelebihan lainnya seperti memberikan sebagai Typeganti nama kelas dalam sebuah string. Mengapa Anda mengalami masalah seperti itu adalah cerita yang berbeda. Inilah beberapa orang yang membutuhkannya:

deepee1
sumber
2
Ini terbukti bermanfaat bagi saya. Dalam kasus saya, kelas berada di namespace yang berbeda, jadi saya harus memastikan bahwa saya menyertakan namespace dalam string ClassName saya (yaitu String ClassName = "My.Namespace.MyFancyObject";).
Scott
1
Anda lupa menambahkan Unwrap (). Anda juga dapat meletakkan null, bukan "MyAssembly", dan sistem akan mencari Assembly saat ini.
Tony
1
Dapatkah saya melakukan sesuatu seperti ini obj = (MyFancyObject)Activator.CreateInstance("MyAssembly", ClassName))tetapi alih-alih melakukan casting dengan tipe tersebut. Transmisikan dengan tipe yang terbuat dari ClassName? Seperti ini Type type = Type.GetType(ClassName);obj = (type )Activator.CreateInstance("MyAssembly", ClassName))?
rluks
1
Apa perbedaan di atas dari: MyFancyObject obj = new MyFancyObject?
Ed Landau
1
@ Ed Landau Perbedaannya adalah Anda dapat membuat instance objek pada waktu proses yang tidak Anda ketahui jenisnya pada waktu kompilasi. Misalnya jika Anda sedang membangun sistem plugin untuk program Anda. Tautan dalam jawaban dapat memberi Anda beberapa gagasan tentang kapan tidak mungkin untuk hanya menulis MyFancyObject obj = new MyFancyObject (). Ini sering kali digabungkan dengan penggunaan refleksi secara umum. Anda juga dapat memeriksa stackoverflow.com/questions/9409293/… untuk penjelasan lainnya.
deepee1
47

Saya bisa memberikan contoh mengapa menggunakan sesuatu seperti itu. Pikirkan game di mana Anda ingin menyimpan level dan musuh Anda dalam file XML. Saat Anda mengurai file ini, Anda mungkin memiliki elemen seperti ini.

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

apa yang dapat Anda lakukan sekarang adalah, membuat objek yang ditemukan di file level Anda secara dinamis.

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

Ini sangat berguna, untuk membangun lingkungan yang dinamis. Tentu saja juga memungkinkan untuk menggunakan ini untuk skenario Plugin atau addin dan banyak lagi.

dowhilefor
sumber
5
Saya mengerti bahwa itu adalah untuk membuat contoh baru dari suatu tipe, tapi ini adalah contoh sederhana yang bagus mengapa seseorang ingin melakukannya.
jamiebarrow
14

Teman baik saya MSDN dapat menjelaskannya kepada Anda, dengan sebuah contoh

Berikut adalah kode jika tautan atau konten berubah di masa mendatang:

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
Claus Jørgensen
sumber
1
Kemungkinan tidak akan terjadi pada MSDN, dan menyalin konten di sini hampir merupakan pelanggaran hak cipta;)
Claus Jørgensen
13
Kamu benar. Secara pribadi saya merasa asas ini juga berfungsi untuk memberikan jawaban yang lebih baik. Saya sering datang ke SO dengan banyak pikiran dari proyek saya saat ini. Saya biasanya hanya ingin jawaban yang sederhana dan langsung, jadi saya bisa melanjutkan dari bagian yang saya tinggalkan. Saya benci harus membuka artikel, yang terkadang bahkan menautkan ke artikel lain. Banyak penjawab tidak menyadari bahwa banyak orang tidak datang ke sini dengan waktu luang mereka untuk membaca beberapa artikel, dengan banyak perkenalan dan pembicaraan yang tidak perlu. Merangkum secara singkat bagian penting dari artikel bagus adalah kunci dari beberapa jawaban terhebat yang pernah saya lihat.
Aske B.
10

Anda juga bisa melakukan ini -

var handle = Activator.CreateInstance("AssemblyName", 
                "Full name of the class including the namespace and class name");
var obj = handle.Unwrap();
William
sumber
Unwrap () adalah bagian yang hilang. :)
Tony
Saya tidak dapat menemukan metode 'Unwrap ()' di atas untuk digunakan (seperti di atas). Apakah ada yang berubah di .NET API baru?
Sam
Itu masih ada di namespace Sistem.
William
2
Bisakah Anda memberikan penjelasan tambahan tentang apa .Unwrap()tepatnya dan bagaimana hal ini berkaitan dengan solusi lain?
Jeroen Vannevel
@ Sam itu pada kelebihan yang berbeda di CreateInstancemana ia kembali System.Runtime.Remoting.ObjectHandle.
nawfal
9

Contoh yang baik adalah yang berikutnya: misalnya Anda memiliki sekumpulan Logger dan Anda mengizinkan pengguna untuk menentukan jenis yang akan digunakan dalam runtime melalui file konfigurasi.

Kemudian:

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

ATAU kasus lainnya adalah ketika Anda memiliki pabrik entitas umum, yang membuat entitas, dan juga bertanggung jawab atas inisialisasi entitas dengan data yang diterima dari DB:

(pseudocode)

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;
}
sll
sumber
Ini tidak berhasil, typeof(loggerType)mengakibatkanloggerType is a variable and used like a type
Barkermn01
3

Itu Activator.CreateInstance Metode menciptakan sebuah instance dari tipe tertentu menggunakan konstruktor yang paling cocok dengan parameter yang ditentukan.

Misalnya, Anda memiliki nama tipe sebagai string, dan Anda ingin menggunakan string untuk membuat instance dari tipe itu. Anda bisa menggunakan Activator.CreateInstanceuntuk ini:

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

Berikut artikel MSDN yang menjelaskan aplikasinya secara lebih rinci:

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

James Johnson
sumber
5
Atau Anda bisa menggunakan new Foo(). Saya pikir OP menginginkan contoh yang lebih realistis.
Konrad Rudolph
1
Saya setuju dengan @Konrad. Alasan penggunaan CreateInstanceadalah jika Anda tidak mengetahui jenis objek yang akan Anda buat pada waktu desain. Dalam contoh ini, Anda mengetahui dengan jelas jenisnya Fookarena Anda mentransmisikannya sebagai jenis Foo. Anda tidak akan pernah melakukan ini karena Anda bisa melakukannya Foo foo = new Foo().
theyetiman
1

Membangun dari deepee1 dan ini , berikut ini cara menerima nama kelas dalam string, dan kemudian menggunakannya untuk membaca dan menulis ke database dengan LINQ. Saya menggunakan "dinamis" daripada casting deepee1 karena memungkinkan saya untuk menetapkan properti, yang memungkinkan kita untuk secara dinamis memilih dan beroperasi pada tabel yang kita inginkan.

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);
DharmaTurtle
sumber
0

Mengapa Anda menggunakannya jika Anda sudah mengetahui kelas tersebut dan akan menayangkannya? Mengapa tidak melakukannya dengan cara lama dan membuat kelas seperti Anda selalu membuatnya? Tidak ada keuntungan untuk ini dibandingkan dengan cara yang biasa dilakukan. Adakah cara untuk mengambil teks dan mengoperasikannya sebagai berikut:

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

Jika saya sudah tahu ini adalah Pizza, tidak ada keuntungan untuk:

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

tetapi saya melihat keuntungan besar pada metode Sihir jika itu ada.

pengguna8659016
sumber
0

Ditambah dengan refleksi, saya menemukan Activator.CreateInstance sangat membantu dalam memetakan hasil prosedur tersimpan ke kelas khusus seperti yang dijelaskan dalam jawaban berikut .

berguna
sumber