Aktivatörün Amacı Örnek ile Örnek Oluşturma?


124

Birisi Activator.CreateInstance()amacı ayrıntılı olarak açıklayabilir mi?


6
Muhtemelen daha büyük dokümantasyon ve örnek genel aşırı yüklemelerde mevcut değildir. Gelen belgelerin aşırı yüklenmeyle CreateInstance(Type type)eşleşmesini tavsiye ederim CreateInstance<T>().
Claus Jørgensen

4
MSDN sayfasında yalnızca tek bir açıklayıcı satır vardır: "Yerel olarak veya uzaktan nesne türleri oluşturma veya mevcut uzak nesnelere referanslar alma yöntemleri içerir. Bu sınıf miras alınamaz." msdn.microsoft.com/en-us/library/system.activator.aspx
gonzobrains

2
Buraya Java geçmişinden geldiyseniz c#.net, bunu yapmanın yolu budur Object xyz = Class.forName(className).newInstance();.
2018'de

Burada bunun için daha iyi belgeler var .
jpaugh

Yanıtlar:


149

MyFancyObjectAşağıdaki gibi bir sınıfınız olduğunu varsayalım :

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

Dönmenizi sağlar:

String ClassName = "MyFancyObject";

içine

MyFancyObject obj;

kullanma

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

ve daha sonra aşağıdaki gibi şeyler yapabilir:

obj.A = 100;

Amacı bu. TypeBir dizede sınıf adı yerine a sağlamak gibi birçok başka aşırı yüklemeye de sahiptir . Neden böyle bir problemin olsun farklı bir hikaye. İşte buna ihtiyacı olan bazı insanlar:


2
Bu benim için faydalı oldu. Benim durumumda, sınıf farklı bir ad alanındaydı, bu nedenle ad alanını SınıfAdı dizeme (yani String ClassName = "My.Namespace.MyFancyObject";) dahil ettiğimden emin olmalıydım .
Scott

1
Unwrap () eklemeyi unuttunuz. "MyAssembly" yerine null da koyabilirsiniz ve sistem mevcut Montajı arayacaktır.
Tony

1
Bunun gibi bir şey yapabilir miyim obj = (MyFancyObject)Activator.CreateInstance("MyAssembly", ClassName))ama türle döküm yapmak yerine. ClassName'den yapılan türle döküm? Bunun gibi Type type = Type.GetType(ClassName);obj = (type )Activator.CreateInstance("MyAssembly", ClassName))mi?
rluks

1
Yukarıdakinin şundan farkı: MyFancyObject obj = new MyFancyObject?
Ed Landau

1
@Ed Landau Aradaki fark, çalışma zamanında, türünü bilmediğiniz bir nesneyi derleme zamanında başlatabilmenizdir. Örneğin, programınız için bir eklenti sistemi oluşturuyorsanız. Yanıttaki bağlantılar, ne zaman sadece MyFancyObject obj = new MyFancyObject () yazmanın mümkün olmayacağı konusunda size bazı fikirler verebilir. Bu, çoğu zaman genel olarak yansıma kullanımıyla birleştirilir. Ayrıca başka bir açıklama için stackoverflow.com/questions/9409293/… adresini de kontrol edebilirsiniz .
deepee1

47

Size neden böyle bir şey kullanmanız gerektiğine dair bir örnek verebilirim. Seviyenizi ve düşmanlarınızı bir XML dosyasında saklamak istediğiniz bir oyun düşünün. Bu dosyayı ayrıştırdığınızda, bunun gibi bir öğeye sahip olabilirsiniz.

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

şimdi yapabileceğiniz şey, seviye dosyanızda bulunan nesneleri dinamik olarak oluşturmaktır.

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

Bu, dinamik ortamlar oluşturmak için çok kullanışlıdır. Elbette bunu Eklenti veya eklenti senaryoları ve daha fazlası için kullanmak da mümkündür.


5
Bunun bir türün yeni bir örneğini yaratmak olduğunu anladım, ancak bu neden birinin bunu yapmak istediğine dair güzel ve basit bir örnek.
jamiebarrow

14

İyi arkadaşım MSDN bunu size bir örnekle açıklayabilir

Gelecekte bağlantının veya içeriğin değişmesi durumunda kullanılacak kod:

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 için olur ve burada içerik kopyalama olası değildir neredeyse telif hakkının ihlali;)
Claus Jørgensen

13
Haklısın. Şahsen ben ilkenin daha iyi cevaplar vermeye çalıştığını hissediyorum. SO'ya sık sık şu anki projemden aklımda birçok şeyle gelirim. Genelde basit ve isabetli bir cevap istiyorum, böylece kaldığım yerden devam edebilirim. Bazen başka makalelere bağlantı veren makaleler açmak zorunda kalmaktan nefret ediyorum. Cevap verenlerin çoğu, pek çok insanın buraya ellerinde birkaç makaleyi okumak için, bir sürü gereksiz tanışma ve konuşma ile gelmediğinin farkında değil. İyi bir makalenin önemli kısımlarını kısaca özetlemek, gördüğüm en büyük cevaplardan bazılarının anahtarıdır.
Aske B.

10

Bunu da yapabilirsiniz -

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

Unwrap () eksik parçaydı. :)
Tony

Kullanmak için yukarıdaki 'Unwrap ()' yöntemini bulamıyorum (yukarıdaki gibi). Yeni .NET API'lerinde bir şey değişti mi?
Sam

Sistem ad alanında hala orada.
William

2
.Unwrap()Tam olarak neyin işe yaradığı ve bunun diğer çözümlerle nasıl bir ilişkisi olduğu konusunda ek açıklama yapabilir misiniz ?
Jeroen Vannevel

@Sam, CreateInstancedöndüğü yerin farklı bir aşırı yüklemesinde System.Runtime.Remoting.ObjectHandle.
nawfal

9

Bundan sonra iyi bir örnek olabilir: örneğin, bir dizi Kaydediciniz var ve kullanıcının, yapılandırma dosyası aracılığıyla çalışma zamanında kullanılacak türü belirlemesine izin veriyorsunuz.

Sonra:

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

VEYA başka bir durum, varlık oluşturan ve aynı zamanda DB'den alınan verilerle bir varlığın başlatılmasından sorumlu olan bir ortak varlık fabrikasına sahip olduğunuzdur:

(Yalancı kod)

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

Bu işe yaramıyor, typeof(loggerType)sonuçloggerType is a variable and used like a type
Barkermn01

3

Activator.CreateInstanceYöntem belirlenen parametreleri en iyi eşleştiğini yapıcısı kullanarak belirtilen türde bir örneğini oluşturur.

Örneğin, tür adını bir dizge olarak aldığınızı ve dizeyi bu türden bir örnek oluşturmak için kullanmak istediğinizi varsayalım. Bunun için kullanabilirsiniz Activator.CreateInstance:

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

İşte uygulamasını daha ayrıntılı olarak açıklayan bir MSDN makalesi:

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


5
Ya da sadece kullanabilirsin new Foo(). Bence OP daha gerçekçi bir örnek istedi.
Konrad Rudolph

1
@Konrad'a katılıyorum. Kullanmanın nedeni CreateInstance, tasarım zamanında başlatacağınız nesnenin türünü bilmiyorsanız. Bu örnekte, tür Fooolarak yayınladığınız için bunun bir tür olduğunu açıkça biliyorsunuz Foo. Bunu asla yapmazsın çünkü yapabilirsin Foo foo = new Foo().
theyetiman

1

Deepee1 kapalı Bina ve bu , burada bir dizede bir sınıf adı kabul edin ve sonra da LINQ ile bir veritabanına okuma ve yazma için kullanmak nasıl. Deepee1'in dönüştürmesi yerine "dinamik" kullanıyorum çünkü özellikleri atamama izin veriyor, bu da bizim istediğimiz herhangi bir tabloyu dinamik olarak seçmemizi ve çalıştırmamızı sağlıyor.

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

Sınıfı zaten biliyorsan ve onu oyuncu kadrosuna alacak olsaydın neden kullanasın ki? Neden bunu eski moda bir şekilde yapıp, sınıfı her zaman başarabildiğiniz gibi yapmıyorsunuz? Normal şekilde yapılmasına göre bunun hiçbir avantajı yok. Metni alıp bu şekilde işlemenin bir yolu var mı:

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

Pizza olduğunu zaten biliyorsam, bunun bir avantajı yok:

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

ancak eğer varsa Magic yönteminin büyük bir avantaj olduğunu görüyorum.


0

Yansıma ile birleştiğinde, Activator.CreateInstance'in , aşağıdaki yanıtta açıklandığı gibi, saklı yordam sonucunu özel bir sınıfa eşleştirmede çok yardımcı olduğunu buldum .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.