Назначение Activator.CreateInstance с примером?


124

Может кто-нибудь Activator.CreateInstance()подробно объяснить цель?


6
Вероятно, что более подробная документация и пример недоступны в общих перегрузках. Я бы посоветовал, чтобы документация из CreateInstance(Type type)была согласована с CreateInstance<T>()перегрузкой.
Клаус Йоргенсен

4
На странице MSDN есть только одна пояснительная строка: «Содержит методы для создания типов объектов локально или удаленно или для получения ссылок на существующие удаленные объекты. Этот класс не может быть унаследован». msdn.microsoft.com/en-us/library/system.activator.aspx
gonzobrains

2
Если вы пришли сюда из опыта работы с Java, это правильный c#.netспособ Object xyz = Class.forName(className).newInstance();.
SNag 05

Там лучше документация для этого здесь .
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 (). Вы также можете указать null вместо «MyAssembly», и система будет искать текущую сборку.
Тони

1
Могу я сделать что-то подобное, obj = (MyFancyObject)Activator.CreateInstance("MyAssembly", ClassName))но вместо приведения типа. Отливать с типом из ClassName? Как это Type type = Type.GetType(ClassName);obj = (type )Activator.CreateInstance("MyAssembly", ClassName))?
rluks

1
Чем вышеупомянутое отличается от: MyFancyObject obj = new MyFancyObject?
Эд Ландау

1
@Ed Landau Разница в том, что вы можете создать экземпляр объекта во время выполнения, если не знаете его тип во время компиляции. Например, если вы создавали систему плагинов для своей программы. Ссылки в ответе могут дать вам некоторые идеи о том, когда было бы невозможно просто написать MyFancyObject obj = new MyFancyObject (). Это часто сочетается с использованием отражения в целом. Вы также можете проверить stackoverflow.com/questions/9409293/… для еще одного описания.
deepee1 02

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, а копирование содержимого здесь почти нарушает авторские права;)
Клаус Йоргенсен

13
Ты прав. Лично я считаю, что этот принцип работает и для получения более точных ответов. Я часто прихожу в SO, имея в виду многое из моего текущего проекта. Обычно мне нужен простой и точный ответ, чтобы я мог продолжить с того места, на котором остановился. Я ненавижу открывать статьи, которые иногда даже ссылаются на другие статьи. Многие респонденты не понимают, что многие люди приходят сюда не со временем, чтобы прочитать несколько статей с кучей ненужных представлений и разговоров. Краткое изложение важных частей хорошей статьи - ключ к некоторым из лучших ответов, которые я видел.
Aske B.

10

Вы также можете сделать это -

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

Unwrap () был недостающим элементом. :)
Тони

Я не могу найти метод Unwrap () выше для использования (как указано выше). Что-то изменилось в новых .NET API?
Сэм

Он все еще находится в пространстве имен System.
Уильям

2
Не могли бы вы дать дополнительные пояснения о том, .Unwrap()что именно и как это связано с другими решениями?
Йерун Ванневель

@Sam это другая перегрузка, CreateInstanceгде он возвращается System.Runtime.Remoting.ObjectHandle.
nawfal

9

Хорошим примером может быть следующий: например, у вас есть набор регистраторов, и вы позволяете пользователю указывать тип, который будет использоваться во время выполнения, через файл конфигурации.

Затем:

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

ИЛИ другой случай, когда у вас есть фабрика общих сущностей, которая создает сущность, а также отвечает за инициализацию сущности данными, полученными из БД:

(Псевдокод)

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 05

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(). Я думаю, ОП хотел более реалистичный пример.
Конрад Рудольф

1
Я согласен с @Konrad. Причина использования CreateInstanceзаключается в том, что вы не знаете тип объекта, который вы собираетесь создать во время разработки. В этом примере вы четко знаете, что это тип, Fooпоскольку вы приводите его как тип Foo. Вы бы никогда этого не сделали, потому что можете просто сделать Foo foo = new Foo().
heetiman

1

Основываясь на deepee1 и этом , вот как принять имя класса в строке, а затем использовать его для чтения и записи в базу данных с помощью 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();

но я вижу огромное преимущество метода Magic, если он существует.


0

В сочетании с отражением я обнаружил, что Activator.CreateInstance очень полезен при сопоставлении результата хранимой процедуры с настраиваемым классом, как описано в следующем ответе .

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.