Você pode compilar uma expressão simples de lambda para obter seu delegado.
var del = Expression.Lambda<Func<IMyInterface>>(Expression.New(type)).Compile();
Pergunta
Eu tenho um tipo criado em tempo de execução (por meio da compilação da CodEdom) e implementa uma interface conhecida (no momento da compilação).
Suponha que a interface seja IMyInterface
, e eu tenho a instância do tipo Type myType
que adquiri da Assembléia, acabei de compilar a partir do codificador. A classe que myType
representa implementos IMyInterface
.
Eu gostaria de obter um delegado Func<IMyInterface>
que, quando invocado, retornará uma instância de myType
.
Algo que eu gostaria de ligar dessa maneira:
Func<IMyInterface> createObject = GetObjectCreator<IMyInterface>(myType);
IMyInterface myObject = createObject();
Eu sei que se eu tiver um MethodInfo m
Para um método sem parâmetros que retorna uma instância do objeto MyType, então eu poderia fazer algo assim:
Func<IMyInterface> createObject =
( Func<IMyInterface> )Delegate.CreateDelegate(typeof(Func<IMyInterface>), m);
Mas se eu não tenho esse método, e a única coisa que tenho é o construtor sem parâmetros do tipo, como faço para obter esse delegado?
Embora a resposta de Fsimonazzi tenha feito exatamente o que eu estava pedindo, minha abordagem foi um pouco diferente.
Desde que eu controlo a criação e compilação do myType
Tipo, adicionei um método estático público que retorna uma instância desse tipo. Então, depois de compilar esse tipo, obtive uma instância do Methodinfo para esse método e criei o delegado desejado delegate.createlegate.
CodeTypeDeclaration type = new CodeTypeDeclaration
{
Name = "MyClass",
IsClass = true,
TypeAttributes = TypeAttributes.Public
};
type.BaseTypes.Add(new CodeTypeReference(typeof(IMyInterface)));
// fullName is the full name of the myType (including namespace)
var staticInstantiator = new CodeMemberMethod
{
Name = "__Instantiator",
ReturnType = new CodeTypeReference("MyNamespace.MyClass"),
Attributes = MemberAttributes.Public | MemberAttributes.Static
};
staticInstantiator.Statements.Add(
new CodeMethodReturnStatement(
new CodeObjectCreateExpression("MyNamespace.MyClass")));
type.Members.Add(staticInstantiator);
O código acima gera este código e coloca na declaração de classe
public static MyNamespace.MyClass __Instantiator()
{
return new MyNamespace.MyClass();
}
Agora compilando este código e tendo um myType
Digite a instância para esta classe, eu posso fazer
Func<IMyInterface> createObject = ( Func<IMyInterface> )(
Delegate.CreateDelegate(typeof(Func<IMyInterface>),
myType.GetMethod("__Instantiator")) );
IMyInterface obj = createObject(); // This will call MyClass.__Instantiator()
Solução
Você pode compilar uma expressão simples de lambda para obter seu delegado.
var del = Expression.Lambda<Func<IMyInterface>>(Expression.New(type)).Compile();
Outras dicas
Você pode usar Activator.CreateInstance( type )
para realmente criar uma instância do seu tipo. Se você quer isso recheado em um Func<IMyInterface>
Então você pode simplesmente embrulhá -lo em um lambda:
Func<IMyInterface> createObject = () => (IMyInterface) Activator.CreateInstance( myType );
IMyInterface myObject = createObject();
ATUALIZAR:
Desde Activator.CreateInstance
Evidentemente, não é o que você está procurando (embora eu não tenha muita certeza do porquê), suponho que você possa usar a reflexão para encontrar o construtor sem parâmetros do tipo:
public Func<T> GetObjectCreator<T>( Type type )
{
// I'd probably add additional checks here to see that the
// conversion to T is actually possible.
var ctor = type.GetConstructor( Type.EmptyTypes );
if( ctor == null ) throw new ArgumentException( "type", "Public parameterless constructor not found." )
return () => (T) ctor.Invoke( null );
}