簡體   English   中英

使用Reflection.Emit設置屬性值

[英]Using Reflection.Emit to set a property value

我正在構建一個動態代理來攔截我正在編寫的庫中的一些方法。 我可以成功創建我的代理類型但是當我嘗試實現屬性設置器時,我收到以下錯誤。

System.InvalidProgramException

增加信息:

Common Language Runtime檢測到無效程序。

我的發射器代碼如下:

public void Emit(FieldInfo interceptorField, 
                 MethodInfo method, 
                 TypeBuilder typeBuilder)
{
    // Get the method parameters for any setters.
    ParameterInfo[] parameters = method.GetParameters();
    ParameterInfo parameter = parameters.FirstOrDefault();

    // Define attributes.
    const MethodAttributes MethodAttributes = 
             MethodAttributes.Public | MethodAttributes.HideBySig |
             MethodAttributes.Virtual;

    // Define the method.
    MethodBuilder methodBuilder = typeBuilder.DefineMethod(
        method.Name,
        MethodAttributes,
        CallingConventions.HasThis,
        method.ReturnType,
        parameters.Select(param => param.ParameterType).ToArray());

    ILGenerator il = methodBuilder.GetILGenerator();

    // Set the correct flags to signal the property is managed 
    // and implemented in intermediate language.
    methodBuilder.SetImplementationFlags(
        MethodImplAttributes.Managed | MethodImplAttributes.IL);

    // This is the equivalent to:
    // IInterceptor interceptor = ((IProxy)this).Interceptor;
    // if (interceptor == null)
    // {
    //    throw new NotImplementedException();
    // }
    il.Emit(OpCodes.Ldarg_0);
    il.Emit(OpCodes.Callvirt, GetInterceptor);
    Label skipThrow = il.DefineLabel();
    il.Emit(OpCodes.Dup);
    il.Emit(OpCodes.Ldnull);
    il.Emit(OpCodes.Bne_Un, skipThrow);
    il.Emit(OpCodes.Newobj, NotImplementedConstructor);
    il.Emit(OpCodes.Throw);
    il.MarkLabel(skipThrow);

    // This is equivalent to: 
    // For get
    // return interceptor.Intercept(MethodBase.GetCurrentMethod(), null);
    // For set
    // interceptor.Intercept(MethodBase.GetCurrentMethod(), value);
    il.Emit(OpCodes.Call, GetCurrentMethod);
    il.Emit(parameter == null ? OpCodes.Ldnull : OpCodes.Ldarg_1);
    il.Emit(OpCodes.Call, InterceptorMethod);

    if (method.ReturnType != typeof(void))
    {
        il.Emit(OpCodes.Ret);
    }
}

當使用Telerik JustDecompile查看輸出代碼(一個名為Bat的字符串屬性)時,我得到以下結果:

public override void set_Bat(string str)
{
    IInterceptor interceptor = ((IProxy)this).Interceptor;
    if (interceptor == null)
    {
        throw new NotImplementedException();
    }
    interceptor.Intercept(MethodBase.GetCurrentMethod(), str);
}

使用Reflector時

public override void set_Bat(string str)
{
    IInterceptor interceptor = ((IProxy)this).Interceptor;
    if (interceptor == null)
    {
        throw new NotImplementedException();
    }
}

注意最后一行是如何丟失的。

有任何想法嗎?

事實證明,代碼存在一些問題。

首先,漢斯帕斯特指出我在兩種情況下都沒有回來。

使用以下方法修復了這個問題。

if (method.ReturnType == typeof(void))
{
    il.Emit(OpCodes.Pop);
}

il.Emit(OpCodes.Ret);

此外,我正在調用MethodBase.GetCurrentMethod() ,這將無法正常工作。 我需要使用MethodBase.GetMethodFromHandle代替並發出

il.Emit(OpCodes.Ldtoken, method);
il.Emit(OpCodes.Call, GetMethodFromHandle);

確保MethodInfo上下文正確指向基類型。

這一切都產生了:

public override void set_Bat(string value)
{
    IInterceptor interceptor = this.Interceptor;
    if (interceptor == null)
    {
        throw new NotImplementedException();
    }
    interceptor.Intercept(methodof(Bar.set_Bat), value);
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM