Objetivo do Activator.CreateInstance com exemplo?

124

Alguém pode explicar o Activator.CreateInstance()objetivo em detalhes?

Tabriz Atayi
fonte
6
Provavelmente, a documentação e o exemplo maiores não estão disponíveis nas sobrecargas genéricas. Gostaria de encorajar que a documentação de CreateInstance(Type type)seja combinada com a CreateInstance<T>()sobrecarga.
Claus Jørgensen
4
A página MSDN possui apenas uma única linha explicativa: "Contém métodos para criar tipos de objetos local ou remotamente ou obter referências a objetos remotos existentes. Esta classe não pode ser herdada". msdn.microsoft.com/en-us/library/system.activator.aspx
gonzobrains
2
Se você veio aqui de Java, essa é a c#.netmaneira de fazer Object xyz = Class.forName(className).newInstance();.
SNag
Há uma documentação melhor para isso aqui .
jpaugh

Respostas:

149

Digamos que você tenha uma classe chamada MyFancyObjectcomo esta abaixo:

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

Permite ativar:

String ClassName = "MyFancyObject";

Para dentro

MyFancyObject obj;

Usando

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

e pode fazer coisas como:

obj.A = 100;

Esse é o seu propósito. Ele também possui muitas outras sobrecargas, como fornecer um Typenome em vez do nome da classe em uma sequência. Por que você teria um problema como esse é uma história diferente. Aqui estão algumas pessoas que precisavam:

deepee1
fonte
2
Isso se mostrou útil para mim. No meu caso, a classe estava em um espaço para nome diferente, então eu tive que me certificar de incluir o espaço para nome na minha string ClassName (ou seja String ClassName = "My.Namespace.MyFancyObject";).
Scott
1
Você esqueceu de adicionar o Unwrap (). Você também pode colocar nulo, em vez de "MyAssembly", e o sistema pesquisará o Assembly atual.
Tony
1
Posso fazer algo assim, obj = (MyFancyObject)Activator.CreateInstance("MyAssembly", ClassName))mas em vez de transmitir com o tipo Transmitir com o tipo criado a partir do ClassName? Gosta disso Type type = Type.GetType(ClassName);obj = (type )Activator.CreateInstance("MyAssembly", ClassName))?
rluks
1
Qual é a diferença acima de: MyFancyObject obj = new MyFancyObject?
Ed Landau
1
@ Ed Landau A diferença é que você pode instanciar um objeto em tempo de execução que não sabe que é do tipo em tempo de compilação. Por exemplo, se você estava construindo um sistema de plugins para o seu programa. Os links na resposta podem fornecer algumas idéias sobre quando não seria possível escrever MyFancyObject obj = new MyFancyObject (). Muitas vezes, isso costumava ser associado ao uso da reflexão em geral. Você também pode conferir stackoverflow.com/questions/9409293/… para mais uma descrição.
precisa saber é o seguinte
47

Bem, eu posso te dar um exemplo de por que usar algo assim. Pense em um jogo em que você deseja armazenar seu nível e inimigos em um arquivo XML. Ao analisar este arquivo, você pode ter um elemento como este.

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

o que você pode fazer agora é criar dinamicamente os objetos encontrados no seu arquivo de nível.

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

Isso é muito útil para criar ambientes dinâmicos. É claro que também é possível usar isso para cenários de plug-in ou add-in e muito mais.

dowhilefor
fonte
5
Eu entendi que era para criar uma nova instância de um tipo, mas este é um bom exemplo simples de por que alguém iria querer fazer isso.
21812 Jamiebarrow
14

Meu bom amigo MSDN pode explicar isso para você, com um exemplo

Aqui está o código, caso o link ou o conteúdo seja alterado no futuro:

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
Claus Jørgensen
fonte
1
Não deve acontecer para MSDN, e copiar o conteúdo aqui é quase uma violação dos direitos de autor;)
Claus Jørgensen
13
Você está certo. Pessoalmente, sinto que o princípio também funciona para dar melhores respostas. Costumo chegar a SO com muito em mente do meu projeto atual. Normalmente, só quero uma resposta simples e direta, para poder continuar de onde parei. Eu odeio ter que abrir artigos, que às vezes até vinculam a outros artigos. Muitos respondentes não percebem que muitas pessoas não vêm aqui com tempo disponível para ler vários artigos, com inúmeras apresentações e palestras desnecessárias. Resumir brevemente as partes importantes de um bom artigo é a chave para algumas das maiores respostas que já vi.
Aske B.
10

Você também pode fazer isso -

var handle = Activator.CreateInstance("AssemblyName", 
                "Full name of the class including the namespace and class name");
var obj = handle.Unwrap();
William
fonte
O Unwrap () foi a peça que faltava. :)
Tony
Não consigo encontrar o método 'Unwrap ()' acima para usar (como acima). Alguma coisa mudou nas novas APIs .NET?
Sam
Ainda está lá no espaço de nome do sistema.
William
2
Você poderia fornecer uma explicação adicional sobre o que .Unwrap()é preciso e como isso se relaciona com outras soluções?
Jeroen Vannevel
@ Sam está em uma sobrecarga diferente de CreateInstanceonde ele retorna System.Runtime.Remoting.ObjectHandle.
Nawfal #
9

Um bom exemplo pode ser o próximo: por exemplo, você tem um conjunto de Registradores e permite que o usuário especifique o tipo a ser usado no tempo de execução via arquivo de configuração.

Então:

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

OU outro caso é quando você tem uma fábrica de entidades comum, que cria uma entidade, e também é responsável na inicialização de uma entidade pelos dados recebidos do DB:

(pseudo-código)

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;
}
sll
fonte
Isso não funciona, typeof(loggerType)resulta emloggerType is a variable and used like a type
Barkermn01 5/17/17
3

O Activator.CreateInstancemétodo cria uma instância de um tipo especificado usando o construtor que melhor corresponde aos parâmetros especificados.

Por exemplo, digamos que você tenha o nome do tipo como uma sequência e deseja usá-la para criar uma instância desse tipo. Você pode usar Activator.CreateInstancepara isso:

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

Aqui está um artigo do MSDN que explica sua aplicação com mais detalhes:

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

James Johnson
fonte
5
Ou você pode apenas usar new Foo(). Eu acho que o OP queria um exemplo mais realista.
Konrad Rudolph
1
Eu concordo com @Konrad. O motivo do uso CreateInstanceé se você não souber o tipo de objeto que você irá instanciar no momento do design. Neste exemplo, você sabe claramente que é do tipo, Foouma vez que o está convertendo como tipo Foo. Você nunca faria isso porque pode simplesmente fazer Foo foo = new Foo().
theyetiman
1

Com base no deepee1 e isso , veja como aceitar um nome de classe em uma string e, em seguida, usá-lo para ler e gravar em um banco de dados com LINQ. Eu uso "dinâmico" em vez da conversão do deepee1 porque ele me permite atribuir propriedades, o que nos permite selecionar e operar dinamicamente em qualquer tabela que desejar.

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);
DharmaTurtle
fonte
0

Por que você o usaria se você já conhecesse a classe e a apresentasse? Por que não fazer da maneira antiga e fazer da classe como você sempre faz? Não há vantagem nisso sobre o modo como é feito normalmente. Existe uma maneira de pegar o texto e operá-lo assim:

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

Se eu já sei que é uma Pizza, não há vantagem em:

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

mas vejo uma enorme vantagem no método Magic, se existir.

user8659016
fonte
0

Juntamente com a reflexão, achei o Activator.CreateInstance muito útil no mapeamento do resultado do procedimento armazenado para uma classe personalizada, conforme descrito na resposta a seguir .

usefulBee
fonte