Назначение 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.