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.