Cel Activator. Utworzyć Instancję na przykładzie?


124

Czy ktoś może Activator.CreateInstance()szczegółowo wyjaśnić cel?


6
Prawdopodobnie większa dokumentacja i przykład nie są dostępne w ogólnych przeciążeniach. Zachęcam, aby dokumentacja z CreateInstance(Type type)jest dopasowana do CreateInstance<T>()przeciążenia.
Claus Jørgensen

4
Strona MSDN zawiera tylko jeden wiersz z objaśnieniami: „Zawiera metody do lokalnego lub zdalnego tworzenia typów obiektów albo uzyskiwania odwołań do istniejących obiektów zdalnych. Tej klasy nie można dziedziczyć”. msdn.microsoft.com/en-us/library/system.activator.aspx
gonzobrains

2
Jeśli przyjechałeś tutaj ze środowiska Java, to jest c#.netsposób na zrobienie tego Object xyz = Class.forName(className).newInstance();.
SNag

Jest lepsza dokumentacja dla niego tutaj .
jpaugh

Odpowiedzi:


149

Załóżmy, że masz zajęcia o nazwie MyFancyObjecttakiej jak ta poniżej:

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

Pozwala skręcić:

String ClassName = "MyFancyObject";

W

MyFancyObject obj;

Za pomocą

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

a potem może robić takie rzeczy jak:

obj.A = 100;

To jest jego cel. Ma również wiele innych przeciążeń, takich jak podawanie Typezamiast nazwy klasy w ciągu. Dlaczego miałbyś taki problem, to inna historia. Oto kilka osób, które tego potrzebowały:


2
Okazało się to przydatne. W moim przypadku klasa znajdowała się w innej przestrzeni nazw, więc musiałem upewnić się, że dołączyłem przestrzeń nazw do mojego ciągu ClassName (tj String ClassName = "My.Namespace.MyFancyObject";.).
Scott

1
Zapomniałeś dodać Unwrap (). Możesz również wstawić null zamiast „MyAssembly”, a system przeszuka bieżący zestaw.
Tony,

1
Mogę zrobić coś takiego, obj = (MyFancyObject)Activator.CreateInstance("MyAssembly", ClassName))ale zamiast rzucać z typem. Cast z typem wykonanym z ClassName? Jak to Type type = Type.GetType(ClassName);obj = (type )Activator.CreateInstance("MyAssembly", ClassName))?
rluks

1
Czym różni się powyższe od: MyFancyObject obj = new MyFancyObject?
Ed Landau

1
@Ed Landau Różnica polega na tym, że możesz utworzyć instancję obiektu w czasie wykonywania, jeśli nie znasz jego typu w czasie kompilacji. Na przykład, jeśli tworzysz system wtyczek dla swojego programu. Linki w odpowiedzi mogą dać ci kilka pomysłów, kiedy nie byłoby możliwe po prostu napisanie MyFancyObject obj = new MyFancyObject (). Często wiązałoby się to z ogólną refleksją. Możesz również sprawdzić stackoverflow.com/questions/9409293/…, aby uzyskać kolejny opis.
deepee1

47

Cóż, mogę podać przykład, dlaczego warto używać czegoś takiego. Pomyśl o grze, w której chcesz przechowywać swój poziom i wrogów w pliku XML. Kiedy parsujesz ten plik, możesz mieć taki element.

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

co możesz teraz zrobić, to dynamicznie tworzyć obiekty znalezione w pliku poziomu.

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

Jest to bardzo przydatne przy budowaniu dynamicznych środowisk. Oczywiście możliwe jest również użycie tego w scenariuszach wtyczek lub dodatków i nie tylko.


5
Zrozumiałem, że chodziło o utworzenie nowej instancji typu, ale jest to miły, prosty przykład, dlaczego ktoś chciałby to zrobić.
jamiebarrow

14

Mój dobry przyjaciel MSDN może ci to wyjaśnić na przykładzie

Oto kod na wypadek zmiany linku lub treści w przyszłości:

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
Mało prawdopodobne w przypadku MSDN, a kopiowanie zawartości tutaj jest prawie naruszeniem praw autorskich;)
Claus Jørgensen

13
Masz rację. Osobiście uważam, że zasada działa również przy udzielaniu lepszych odpowiedzi. Często przychodzę do SO z myślą o moim obecnym projekcie. Zwykle potrzebuję prostej i konkretnej odpowiedzi, więc mogę kontynuować od miejsca, w którym skończyłem. Nienawidzę otwierać artykułów, które czasami zawierają linki do innych artykułów. Wielu odpowiadających nie zdaje sobie sprawy, że wiele osób nie przychodzi tutaj z wolnymi rękami, aby przeczytać kilka artykułów, z mnóstwem niepotrzebnych wstępów i rozmów. Krótkie podsumowanie ważnych części dobrego artykułu jest kluczem do niektórych z najlepszych odpowiedzi, jakie widziałem.
Aske B.

10

Możesz też to zrobić -

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

Brakującym elementem był Unwrap (). :)
Tony,

Nie mogę znaleźć metody „Unwrap ()” powyżej do użycia (jak wyżej). Czy coś się zmieniło w nowych interfejsach API platformy .NET?
Sam

Nadal jest w przestrzeni nazw System.
William

2
Czy mógłbyś podać dodatkowe wyjaśnienie, co .Unwrap()dokładnie robi i jak to się ma do innych rozwiązań?
Jeroen Vannevel

@Sam, jest w innym przeciążeniu, z CreateInstancektórego wraca System.Runtime.Remoting.ObjectHandle.
nawfal

9

Dobry przykład może być następny: na przykład masz zestaw rejestratorów i pozwalasz użytkownikowi określić typ, który ma być używany w środowisku wykonawczym, za pośrednictwem pliku konfiguracyjnego.

Następnie:

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

LUB inny przypadek to sytuacja, gdy masz wspólną fabrykę jednostek, która tworzy jednostkę i jest również odpowiedzialna za inicjalizację jednostki przez dane otrzymane z DB:

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

To nie działa, typeof(loggerType)skutkujeloggerType is a variable and used like a type
Barkermn01

3

Activator.CreateInstanceMetoda tworzy instancję określonego typu przy użyciu konstruktora, który najlepiej pasuje do podanych parametrów.

Na przykład, powiedzmy, że masz nazwę typu jako ciąg i chcesz użyć tego ciągu do utworzenia wystąpienia tego typu. Możesz użyć Activator.CreateInstancedo tego:

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

Oto artykuł MSDN, który bardziej szczegółowo wyjaśnia jego zastosowanie:

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


5
Lub możesz po prostu użyć new Foo(). Myślę, że PO chciał bardziej realistycznego przykładu.
Konrad Rudolph

1
Zgadzam się z @Konrad. Powodem użycia CreateInstancejest to, że nie znasz typu obiektu, który zamierzasz utworzyć w czasie projektowania. W tym przykładzie wyraźnie wiesz, że jest to typ, Fooponieważ rzutujesz go jako typ Foo. Nigdy byś tego nie zrobił, ponieważ możesz to zrobić Foo foo = new Foo().
themetiman

1

Opierając się na deepee1 i tym , oto jak zaakceptować nazwę klasy w ciągu, a następnie użyć jej do odczytu i zapisu w bazie danych za pomocą LINQ. Używam „dynamicznego” zamiast rzutowania deepee1, ponieważ pozwala mi przypisywać właściwości, co pozwala nam dynamicznie wybierać i operować na dowolnej tabeli.

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

Dlaczego miałbyś go używać, skoro znałeś już klasę i zamierzałeś ją obsadzić? Dlaczego nie zrobić tego w staroświecki sposób i sprawić, by klasa była taka, jak zawsze? Nie ma to żadnej przewagi nad sposobem, w jaki jest to robione normalnie. Czy istnieje sposób, aby wziąć tekst i operować na nim w ten sposób:

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

Jeśli już wiem, że to pizza, nie ma żadnej korzyści, aby:

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

ale widzę ogromną zaletę metody Magic, jeśli taka istnieje.


0

W połączeniu z refleksją odkryłem, że Activator.CreateInstance jest bardzo pomocny w mapowaniu wyniku procedury składowanej na klasę niestandardową, jak opisano w poniższej odpowiedzi .

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.