使用委托调用构造函数

发布于 2024-08-18 07:50:21 字数 1000 浏览 6 评论 0原文

我发现这个但尝试使用它但失败了。

如何使用反射创建对象并通过将其放入委托中来使其快速?

        DynamicMethod dm = new DynamicMethod("MyCtor", t, new Type[] { });            
        var ctor = t.GetConstructor(new Type[] { });
        ILGenerator ilgen = dm.GetILGenerator();
        ilgen.Emit(OpCodes.Ldarg_0);
        ilgen.Emit(OpCodes.Newobj, ctor);
        ilgen.Emit(OpCodes.Ret);
        var d = (Func<T>)dm.CreateDelegate(t);
        dm.Invoke(null, new object[] { });

在将其放入 deleage 之前,我至少尝试调用它,当我执行上述操作时,我收到错误

An unhandled exception of type 'System.Reflection.TargetInvocationException' occurred in mscorlib.dll

附加信息:调用目标已引发异常。

如果我调用 d() 相反,我会得到异常

An unhandled exception of type 'System.ArgumentException' occurred in mscorlib.dll

Additional information: Type must derive from Delegate.

如何将无参数构造函数放入委托中并调用它?

I found this but tried to use it and failed.

How can i create an object using reflections and make it fast by putting it in a delegate?

        DynamicMethod dm = new DynamicMethod("MyCtor", t, new Type[] { });            
        var ctor = t.GetConstructor(new Type[] { });
        ILGenerator ilgen = dm.GetILGenerator();
        ilgen.Emit(OpCodes.Ldarg_0);
        ilgen.Emit(OpCodes.Newobj, ctor);
        ilgen.Emit(OpCodes.Ret);
        var d = (Func<T>)dm.CreateDelegate(t);
        dm.Invoke(null, new object[] { });

Before putting it in a deleage i tried to at least invoke it and when i did above i get the error

An unhandled exception of type 'System.Reflection.TargetInvocationException' occurred in mscorlib.dll

Additional information: Exception has been thrown by the target of an invocation.

If i call d() instead i get the exception

An unhandled exception of type 'System.ArgumentException' occurred in mscorlib.dll

Additional information: Type must derive from Delegate.

How do i put a no param constructor into a delegate and call it?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

落花随流水 2024-08-25 07:50:21

如果您可以访问 .NET 3.5(您使用 Func 建议这样做),您可能会发现 ExpressionILGenerator 更容易

class Foo { }
static void Main() {
    Func<Foo> func = GetCtor<Foo>(); // cache this somewhere!
    Foo foo = func();
}
static Func<T> GetCtor<T>() {
    Type type = typeof(T);
    Expression body = Expression.New(type);
    return Expression.Lambda<Func<T>>(body).Compile();        
}

:易于扩展以使用特定的构造函数、传递参数或添加构造函数后属性绑定;转换、转换等(请参阅此相关答案)。如果您有特定的场景,我很乐意添加一个示例。

另请注意,您应该缓存并重用任何此类构造函数 - 否则您将失去好处(即不要在每次调用时重新创建委托)。

If you have access to .NET 3.5 (which your use of Func<T> suggests), you may find Expression easier than ILGenerator:

class Foo { }
static void Main() {
    Func<Foo> func = GetCtor<Foo>(); // cache this somewhere!
    Foo foo = func();
}
static Func<T> GetCtor<T>() {
    Type type = typeof(T);
    Expression body = Expression.New(type);
    return Expression.Lambda<Func<T>>(body).Compile();        
}

Pretty easy to extend that to use a specific constructor, passing arguments, or adding post-constructor property bindings; casts, conversions, etc (see this related answer). If you have a specific scenario, I'll happily add an example.

Note also that you should cache and re-use any such constructors - otherwise you lose the benefit (i.e. don't recreate the delegate per-call).

苦笑流年记忆 2024-08-25 07:50:21

试试这个 -

Action myCtor = CreateCtor(t, Type.EmptyTypes, typeof(Action));

public static Delegate CreateCtor(Type type, Type[] parameterTypes, Type delegateType, string typeParameterName)
{
    var ctorInfo = type.GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, parameterTypes, null);
    if (ctorInfo == null)
    {
        string parameterString = string.Empty;
        if(parameterTypes.Length > 0)
        {
            string[] parameterStrings = new string[parameterTypes.Length];
            for(int i = 0; i < parameterTypes.Length; ++i)
            {
                parameterStrings[i] = parameterTypes[i].ToString();
            }
            parameterString = string.Join(",", parameterStrings);
        }
        throw new ArgumentException(string.Format("Type '{0}' does not define .ctor({1}).", type, parameterString), typeParameterName);
    }

    bool isVisible = type.IsVisible && (ctorInfo.IsPublic && !ctorInfo.IsFamilyOrAssembly);

    DynamicMethod dynamicCtor = new DynamicMethod(Guid.NewGuid().ToString("N"), type, parameterTypes, ctorInfo.Module, !isVisible);
    var il = dynamicCtor.GetILGenerator();
    for (int i = 0; i < parameterTypes.Length; ++i)
    {
        switch (i)
        {
            case 0: il.Emit(OpCodes.Ldarg_0); break;
            case 1: il.Emit(OpCodes.Ldarg_1); break;
            case 2: il.Emit(OpCodes.Ldarg_2); break;
            case 3: il.Emit(OpCodes.Ldarg_3); break;
            default: il.Emit(OpCodes.Ldarg, i); break;
        }
    }
    il.Emit(OpCodes.Newobj, ctorInfo);
    il.Emit(OpCodes.Ret);
    return dynamicCtor.CreateDelegate(delegateType);
}

Try this -

Action myCtor = CreateCtor(t, Type.EmptyTypes, typeof(Action));

public static Delegate CreateCtor(Type type, Type[] parameterTypes, Type delegateType, string typeParameterName)
{
    var ctorInfo = type.GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, parameterTypes, null);
    if (ctorInfo == null)
    {
        string parameterString = string.Empty;
        if(parameterTypes.Length > 0)
        {
            string[] parameterStrings = new string[parameterTypes.Length];
            for(int i = 0; i < parameterTypes.Length; ++i)
            {
                parameterStrings[i] = parameterTypes[i].ToString();
            }
            parameterString = string.Join(",", parameterStrings);
        }
        throw new ArgumentException(string.Format("Type '{0}' does not define .ctor({1}).", type, parameterString), typeParameterName);
    }

    bool isVisible = type.IsVisible && (ctorInfo.IsPublic && !ctorInfo.IsFamilyOrAssembly);

    DynamicMethod dynamicCtor = new DynamicMethod(Guid.NewGuid().ToString("N"), type, parameterTypes, ctorInfo.Module, !isVisible);
    var il = dynamicCtor.GetILGenerator();
    for (int i = 0; i < parameterTypes.Length; ++i)
    {
        switch (i)
        {
            case 0: il.Emit(OpCodes.Ldarg_0); break;
            case 1: il.Emit(OpCodes.Ldarg_1); break;
            case 2: il.Emit(OpCodes.Ldarg_2); break;
            case 3: il.Emit(OpCodes.Ldarg_3); break;
            default: il.Emit(OpCodes.Ldarg, i); break;
        }
    }
    il.Emit(OpCodes.Newobj, ctorInfo);
    il.Emit(OpCodes.Ret);
    return dynamicCtor.CreateDelegate(delegateType);
}
沉溺在你眼里的海 2024-08-25 07:50:21

构造函数没有参数,因此您不应在堆栈上加载参数 ilgen.Emit(OpCodes.Ldarg_0)

class Program
{
    static void Main()
    {
        var t = typeof(Program);
        var dm = new DynamicMethod("MyCtor", t, new Type[0], t.Module);
        var ctor = t.GetConstructor(new Type[0]);
        ILGenerator ilgen = dm.GetILGenerator();
        ilgen.Emit(OpCodes.Newobj, ctor);
        ilgen.Emit(OpCodes.Ret);
        var del = (Func<Program>)dm.CreateDelegate(typeof(Func<Program>));
        var instance = del();
        Console.WriteLine(instance);
    }
}

There are no arguments to the constructor so you should not load arguments on the stack ilgen.Emit(OpCodes.Ldarg_0):

class Program
{
    static void Main()
    {
        var t = typeof(Program);
        var dm = new DynamicMethod("MyCtor", t, new Type[0], t.Module);
        var ctor = t.GetConstructor(new Type[0]);
        ILGenerator ilgen = dm.GetILGenerator();
        ilgen.Emit(OpCodes.Newobj, ctor);
        ilgen.Emit(OpCodes.Ret);
        var del = (Func<Program>)dm.CreateDelegate(typeof(Func<Program>));
        var instance = del();
        Console.WriteLine(instance);
    }
}
吹泡泡o 2024-08-25 07:50:21

构造委托的通用方法,直接调用构造函数。
自动搜索具有给定委托类型签名的给定类型的构造函数并构造该类型的委托。此处的代码:

/// <summary>
/// Reflective object construction helper.
/// All methods are thread safe.
/// </summary>
public static class Constructor
{
    /// <summary>
    /// Searches an instanceType constructor with delegateType-matching signature and constructs delegate of delegateType creating new instance of instanceType.
    /// Instance is casted to delegateTypes's return type. 
    /// Delegate's return type must be assignable from instanceType.
    /// </summary>
    /// <param name="delegateType">Type of delegate, with constructor-corresponding signature to be constructed.</param>
    /// <param name="instanceType">Type of instance to be constructed.</param>
    /// <returns>Delegate of delegateType wich constructs instance of instanceType by calling corresponding instanceType constructor.</returns>
    public static Delegate Compile(Type delegateType,Type instanceType)
    {
        if (!typeof(Delegate).IsAssignableFrom(delegateType))
        {
            throw new ArgumentException(String.Format("{0} is not a Delegate type.",delegateType.FullName),"delegateType");
        }
        var invoke = delegateType.GetMethod("Invoke");
        var parameterTypes = invoke.GetParameters().Select(pi => pi.ParameterType).ToArray();
        var resultType = invoke.ReturnType;
        if(!resultType.IsAssignableFrom(instanceType))
        {
            throw new ArgumentException(String.Format("Delegate's return type ({0}) is not assignable from {1}.",resultType.FullName,instanceType.FullName));
        }
        var ctor = instanceType.GetConstructor(
            BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, parameterTypes, null);
        if(ctor == null)
        {
            throw new ArgumentException("Can't find constructor with delegate's signature","instanceType");
        }
        var parapeters = parameterTypes.Select(Expression.Parameter).ToArray();

        var newExpression = Expression.Lambda(delegateType,
            Expression.Convert(Expression.New(ctor, parapeters), resultType),
            parapeters);
        var @delegate = newExpression.Compile();
        return @delegate;
    }
    public static TDelegate Compile<TDelegate>(Type instanceType)
    {
        return (TDelegate) (object) Compile(typeof (TDelegate), instanceType);
    }
}

Yappi 项目源代码的一部分。使用它,您可以构造委托,调用给定类型的任何构造函数,包括带参数的构造函数(除了 ref 和 out 参数)。

示例用法:

var newList = Constructor.Compile<Func<int, IList<String>>>(typeof (List<String>));
var list = newList(100);

构造委托后,将其存储在静态字典中或具有泛型参数的类的静态字段中的某个位置。不要每次都构建新的委托。使用一个委托来构造给定类型的多个实例。

Generic method for constructing delegates, calling constructor directly.
Automatically searches constructor in given type with signature of given delegate type and constructs delegate of that type. Code here:

/// <summary>
/// Reflective object construction helper.
/// All methods are thread safe.
/// </summary>
public static class Constructor
{
    /// <summary>
    /// Searches an instanceType constructor with delegateType-matching signature and constructs delegate of delegateType creating new instance of instanceType.
    /// Instance is casted to delegateTypes's return type. 
    /// Delegate's return type must be assignable from instanceType.
    /// </summary>
    /// <param name="delegateType">Type of delegate, with constructor-corresponding signature to be constructed.</param>
    /// <param name="instanceType">Type of instance to be constructed.</param>
    /// <returns>Delegate of delegateType wich constructs instance of instanceType by calling corresponding instanceType constructor.</returns>
    public static Delegate Compile(Type delegateType,Type instanceType)
    {
        if (!typeof(Delegate).IsAssignableFrom(delegateType))
        {
            throw new ArgumentException(String.Format("{0} is not a Delegate type.",delegateType.FullName),"delegateType");
        }
        var invoke = delegateType.GetMethod("Invoke");
        var parameterTypes = invoke.GetParameters().Select(pi => pi.ParameterType).ToArray();
        var resultType = invoke.ReturnType;
        if(!resultType.IsAssignableFrom(instanceType))
        {
            throw new ArgumentException(String.Format("Delegate's return type ({0}) is not assignable from {1}.",resultType.FullName,instanceType.FullName));
        }
        var ctor = instanceType.GetConstructor(
            BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, parameterTypes, null);
        if(ctor == null)
        {
            throw new ArgumentException("Can't find constructor with delegate's signature","instanceType");
        }
        var parapeters = parameterTypes.Select(Expression.Parameter).ToArray();

        var newExpression = Expression.Lambda(delegateType,
            Expression.Convert(Expression.New(ctor, parapeters), resultType),
            parapeters);
        var @delegate = newExpression.Compile();
        return @delegate;
    }
    public static TDelegate Compile<TDelegate>(Type instanceType)
    {
        return (TDelegate) (object) Compile(typeof (TDelegate), instanceType);
    }
}

is part of Yappi project's sources. Using it you can construct delegate calling any constructor of given type, including constructor with parameters (except ref and out parameters).

Sample usage:

var newList = Constructor.Compile<Func<int, IList<String>>>(typeof (List<String>));
var list = newList(100);

After construction of delegate, store it somewhere in static dictionary or in static field of class with generic parameter. Don't construct new delegate each time. Use one delegate for constructing multiple instances of given type.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文