替换属性设定器方法

时间:2018-09-05 07:31:14

标签: c# pointers replace setter methodinfo

public delegate void SetProp(object obj);

void Main()
{
    TestObj obj = new TestObj();

    SetProp setPropDel = (SetProp)SetProp.CreateDelegate(typeof(SetProp), 
    obj, obj.GetSetPropDelegate().GetMethodInfo());
    MethodInfo setPropMethod = setPropDel.GetMethodInfo();

    ///Replacing Count Set-Method Pointer with new Method
    typeof(TestObj).GetProperty("Count").GetSetMethod().ReplaceMethodPtr(setPropMethod);
    obj.Count = 1;

}

public class TestObj
{
    public SetProp GetSetPropDelegate() => SetPropValue;

    private void SetPropValue(object obj) => Console.WriteLine(obj); ///<--- NullReferenceException obj is null.

    public int Count { get; set; }

}

您好,我试图在我的类TestObj中将私有set-Method替换为自动属性“ Count”。

替换本身有效。因为当我使用'obj.Count = 1'这样的setter时,新方法被调用了。

我的问题是:是否可以将参数传递给此新方法? 我至少需要分配给Count-Property的新值。在这种情况下:1。

我的目标是可以在调用新的Set-Method时替换自动属性的Set-Methods引发事件,并且还保留Set-Method的基本功能。

我希望我想实现的目标很明确。我可能在这里遇到了不可能的事情,但是我敢肯定,很多人对发生的事情有了更好的了解。

感谢阅读。

1 个答案:

答案 0 :(得分:0)

我想分享我如何解决这个问题。

我编写了一个具有更多功能的整个库,例如在特定场合或特定场合引发的事件。但是对于答案,我想将其分解为最简单的示例。

void Main()
{
    MethodInfo targetMethod = typeof(TargetObj).GetProperty("Count").GetSetMethod();
    MethodInfo injectMethod = typeof(InjectObj).GetMethod("SetCount");

    targetMethod.InjectMethod(injectMethod);

    var targetInstance = new TargetObj();

    targetInstance.Count = 3;
}

public class TargetObj
{
    public int Count { get; set; }
}

public class InjectObj
{
    public void SetCount(int value)
    {
        GetBackingField(this, "Count").SetValue(this, value);
        Console.WriteLine($"Count has been set to [{value}]");
    }
}

public static FieldInfo GetBackingField(object obj, string propertyName) => obj.GetType().GetField($"<{propertyName}>k__BackingField", BindingFlags.Instance | BindingFlags.NonPublic);

如果运行此代码,则控制台输出为:     计数已设置为[3]

使用这种方法的可能性是无限的,但是我想快速了解一下我如何实现这一目标。

请注意,我使用Linqpad进行了此示例。

我不想不必要地加长帖子,但是我需要包括MethodInfo扩展方法“ InjectMethod”,以全面了解正在发生的事情。

public static class MethodInfoExtensions
{
    public static void InjectMethod(this MethodInfo target, MethodInfo inject)
    {
        RuntimeHelpers.PrepareMethod(inject.MethodHandle);
        RuntimeHelpers.PrepareMethod(target.MethodHandle);

        unsafe
        {
            if (IntPtr.Size == 4)
            {
                int* inj = (int*)inject.MethodHandle.Value.ToPointer() + 2;
                int* tar = (int*)target.MethodHandle.Value.ToPointer() + 2;

                if (Debugger.IsAttached)
                {
                    byte* injInst = (byte*)*inj;
                    byte* tarInst = (byte*)*tar;

                    int* injSrc = (int*)(injInst + 1);
                    int* tarSrc = (int*)(tarInst + 1);

                    *tarSrc = (((int)injInst + 5) + *injSrc) - ((int)tarInst + 5);
                }
                else
                {
                    *tar = *inj;
                }
            }
            else
            {
                long* inj = (long*)inject.MethodHandle.Value.ToPointer() + 1;
                long* tar = (long*)target.MethodHandle.Value.ToPointer() + 1;

                if (Debugger.IsAttached)
                {
                    byte* injInst = (byte*)*inj;
                    byte* tarInst = (byte*)*tar;

                    int* injSrc = (int*)(injInst + 1);
                    int* tarSrc = (int*)(tarInst + 1);

                    *tarSrc = (((int)injInst + 5) + *injSrc) - ((int)tarInst + 5);
                }
                else
                {
                    *tar = *inj;
                }
            }
        }
    }
}

使用这种方法替换,我建议仅用于测试目的,或者建议将其用作调试工具。 我很确定将其实施到真正的发布软件中会产生比解决方案更多的问题。