【问题标题】:Create delegate from a constructor of unknown type implementing a known interface从实现已知接口的未知类型的构造函数创建委托
【发布时间】:2013-12-19 15:15:21
【问题描述】:

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

假设接口是IMyInterface,我有一个类型实例Type myType,它是从我刚刚从CodeDOM 编译的程序集中获得的。 myType代表的类实现了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 类型的创建和编译,所以我添加了一个返回该类型实例的公共静态方法。然后,在编译完这个类型之后,我得到了这个方法的 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()

【问题讨论】:

  • 您忘记实际创建对象,调用 Activator.CreateInstance()。
  • 重点是不要使用这种技术。 GetObjectCreator 应该为我创建实例的方法返回一个委托。如果需要,可以在运行时编译该方法,但我不想每次需要实例时都调用 Activator.CreateInstance()。
  • 你最好考虑一下。单例是一个名字很漂亮的错误。
  • 谁谈过单身?我只会得到一个委托,我可以调用它一百万次,得到一百万个“myType”实例
  • 你不明白我的要求。方法“IMyInterface Create(){ return new myType(); }”只是一种方法,但每次调用都会返回一个新实例。整个问题是我没有这个方法,而且我在编译时不知道“myType”,所以我想在运行时创建它。看看 fsimonazzi 的回答。

标签: c# dynamic reflection code-generation codedom


【解决方案1】:

您可以使用Activator.CreateInstance( type ) 来实际创建您的类型的实例。如果你想把它塞进Func&lt;IMyInterface&gt;,那么你可以把它包装在一个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 );
}

【讨论】:

  • 这两种方法都在创建实例时使用反射,这不是我想要的。我不想要它的原因是反射应该比使用“new T()”的构造函数的实际调用慢,不是吗?所以我想即时获取/创建/编译调用“new T()”(而不是ctor.Invoke)的函数并返回它。然后,我将代表这个函数。所以最终,调用委托将执行“new T()”而不是任何其他反射方式。
  • 嗯,你原来的问题没有提到不使用反射,请澄清一下。您是否真的分析过这些解决方案的性能?如果没有,您只是过早地进行微优化。如果那是您真正想要的,我会采用@fsimonazzi 提供的解决方案。
【解决方案2】:

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

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

【讨论】:

  • 调用委托时不涉及任何反射,对吧?
  • 另外,这行代码是否会在内存中编译并加载额外的程序集?
  • 委托编译后没有反射。该方法被添加到由所有动态方法共享的瞬态程序集(“匿名托管的 DynamicMethods 程序集”)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多