从实现已知接口的未知类型的构造函数创建委托

时间:2013-12-03 14:04:53

标签: c# dynamic reflection code-generation codedom

我有一个在运行时创建的类型(通过CodeDOM编译)并实现一个已知的(在编译时)接口。

假设接口是IMyInterface,并且我从我刚刚从CodeDOM编译的程序集中获取了Type实例Type myTypemyType代表的类实现IMyInterface

我想获得一个委托Func<IMyInterface>,当被调用时,将返回myType的实例。

我想以这种方式打电话:

Func<IMyInterface> createObject = GetObjectCreator<IMyInterface>(myType);
IMyInterface myObject = createObject();

我知道如果我有一个MethodInfo m的无参数方法返回myType对象的实例,那么我可以这样做:

Func<IMyInterface> createObject =
  ( Func<IMyInterface> )Delegate.CreateDelegate(typeof(Func<IMyInterface>), m);

但是如果我没有这样的方法,并且我唯一拥有的是类型的无参数构造函数,那么我该如何获得这个委托呢?

更新

虽然fsimonazzi的答案完全符合我的要求,但我的方法有点不同。

由于我控制myType Type的创建和编译,我添加了一个返回该类型实例的公共静态方法。然后,在编译此类型之后,我为此方法获得了一个MethodInfo实例,并创建了所需的委托调用Delegate.CreateDelegate。

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);

上面的代码生成此代码并将其放入类声明

public static MyNamespace.MyClass __Instantiator()
{
    return new MyNamespace.MyClass();
}

现在编译此代码并为此类设置myType Type实例,我可以

Func<IMyInterface> createObject = ( Func<IMyInterface> )(
    Delegate.CreateDelegate(typeof(Func<IMyInterface>),
                            myType.GetMethod("__Instantiator")) );

IMyInterface obj = createObject(); // This will call MyClass.__Instantiator()

2 个答案:

答案 0 :(得分:3)

您可以编译一个简单的lambda表达式来获取您的委托。

var del = Expression.Lambda<Func<IMyInterface>>(Expression.New(type)).Compile();

答案 1 :(得分:0)

您可以使用Activator.CreateInstance( type )来实际创建您的类型的实例。如果你想在Func<IMyInterface>填充它,那么你可以将它包装在lambda中:

Func<IMyInterface> createObject = () => (IMyInterface) Activator.CreateInstance( myType );
IMyInterface myObject = createObject();

更新:

由于Activator.CreateInstance显然不是你想要的(尽管我不完全确定原因),我想你可以使用反射来找到该类型的无参数构造函数:

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 );
}