4

Reflection Emitを使用して、任意のコンストラクターパラメーターを持つクラスのインスタンスを作成したいと思います。これは私のコードがどのように見えるかです:

public delegate object ObjectActivator(params object[] args);
static void Main(string[] args)
{
    var ao = new { ID = 10000, FName = "Sample", SName = "Name" };
    var t = ao.GetType();
    var info = t.GetConstructor(new Type[] { typeof(int), typeof(string), typeof(string) });
    var objActivatorEmit = GetActivatorEmit(info);
    var obj = createdActivatorEmit(4, "Foo", "Bar");
}
public static ObjectActivator GetActivatorEmit(ConstructorInfo ctor)
{
    ParameterInfo[] paramsInfo = ctor.GetParameters();
    DynamicMethod method = new DynamicMethod("CreateInstance", typeof(object), new Type[] { typeof(object[]) });
    ILGenerator gen = method.GetILGenerator();
    for (int i = 0; i < paramsInfo.Length; i++)
    {
        Type t = paramsInfo[i].ParameterType;
        gen.Emit(OpCodes.Ldarg_0); // Push array (method argument)
        gen.Emit(OpCodes.Ldc_I4, i); // Push i
        gen.Emit(OpCodes.Ldelem_Ref); // Pop array and i and push array[i]
        if( t.IsValueType )
        {
            gen.Emit( OpCodes.Unbox_Any, t ); // Cast to Type t
        }
        else
        {
            gen.Emit( OpCodes.Castclass, t ); //Cast to Type t
        }
    }
    gen.Emit(OpCodes.Newobj, ctor);
    gen.Emit(OpCodes.Ret);
    return (ObjectActivator)method.CreateDelegate(typeof(ObjectActivator));
}

コードMethodAccessExceptionはエラーメッセージとともに失敗しますAttempt by method 'DynamicClass.CreateInstance(System.Object[])' to access method '<>f__AnonymousType1'3<System.Int32,System.__Canon,System.__Canon>..ctor(Int32, System.__Canon, System.__Canon)' failed.

何が問題になっていますか?

4

2 に答える 2

4

エラーメッセージは、匿名型のコンストラクターがパブリックではないことを示しています。匿名型のコンストラクターは常にあると思うので、別のコンストラクターinternalを使用して可視性チェックをスキップする必要があります。DynamicMethod

DynamicMethod method = new DynamicMethod("CreateInstance", typeof(object), new Type[] { typeof(object[]) }, true);

これは、部分的な信頼のシナリオでは機能しないことに注意してください。

于 2012-11-20T18:39:23.323 に答える
2

Reflection.Emitを使用する必要はありませんが、使用しないことをお勧めします。自分が何をしているのかを理解していない限り、または他のAPIでは満たすことができない特別なニーズがない限り、遠ざけるのが最善です。

正しく理解するのがはるかに簡単な3つの選択肢があります。見てみな:

using System;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;

public static class App
{
    public delegate object ObjectActivator(params object[] args);

    public static void Main(string[] args)
    {
        var ao = new { ID = 10000, FName = "Sample", SName = "Name" };
        var t = ao.GetType();
        var info = t.GetConstructor(new[] { typeof(int), typeof(string), typeof(string) });
        if (info == null)
        {
            throw new Exception("Info is null");
        }

        // This uses System.Linq.Expressions to create the delegate
        var activator = GetActivator(info);
        var newObj1 = activator(4, "Foo", "Bar");

        // This invokes the ConstructorInfo directly
        var newObj2 = info.Invoke(new object[] { 4, "Foo", "Bar" });

        // This uses System.Activator to dynamically create the instance
        var newObj3 = Activator.CreateInstance(t, 4, "Foo", "Bar");
    }

    // This uses System.Linq.Expressions to generate a delegate
    public static ObjectActivator GetActivator(ConstructorInfo ctor)
    {
        var args = Expression.Parameter(typeof(object[]), "args");
        var parameters = ctor.GetParameters().Select((parameter, index) => Expression.Convert(Expression.ArrayIndex(args, Expression.Constant(index)), parameter.ParameterType));
        return Expression.Lambda<ObjectActivator>(Expression.New(ctor, parameters), args).Compile();
    }
}

注:この投稿GetActivatorからの方法のインスピレーション

于 2012-11-20T18:03:49.313 に答える