簡體   English   中英

使用Open Delegate訪問struct屬性setter生成異常

[英]Using Open Delegate to access a struct property setter generate exception

為了序列化,我們嘗試生成委托以動態更新一些對象屬性值並將它們存儲到列表中以供進一步使用。 只要我們不嘗試反序列化結構,一切都很好。

我們的代碼基於這篇關於開放代表的文章: http//codeblog.jonskeet.uk/2008/08/09/making-reflection-fly-and-exploring-delegates/

這是我們的代碼,用於處理基於類的對象中的屬性設置器。

    private static System.Action<object, object> ToOpenActionDelegate<T, TParam>(System.Reflection.MethodInfo methodInfo) where T : class
    {
        System.Type parameterType = typeof(TParam);

        // Convert the slow MethodInfo into a fast, strongly typed, open delegate
        System.Action<T, TParam> action = (System.Action<T, TParam>)System.Delegate.CreateDelegate(typeof(System.Action<T, TParam>), methodInfo);

        // Convert the strong typed delegate into some object delegate!
        System.Action<object, object> ret = (object target, object param) => action(target as T, (TParam)System.Convert.ChangeType(param, parameterType));

        return ret;
    }

正如您所猜測的那樣,它不適用於struct。 我發現這篇文章討論了如何在struct中處理open delegate: 如何從struct的實例方法創建一個open Delegate? (實際上,我找到了比這個更多的帖子,但是這個有一個“簡單”的解決方案,例如不使用IL代碼...)

但是,就目前而言,每當我嘗試使用ref參數將屬性setter的methodinfo綁定到委托時,我都會遇到異常。 這是我使用的當前代碼:

    public delegate void RefAction<T, TParam>(ref T arg, TParam param) where T : class;
    private static RefAction<object, object> ToOpenActionDelegate<T, TParam>(System.Reflection.MethodInfo methodInfo) where T : class
    {
        // Convert the slow MethodInfo into a fast, strongly typed, open delegate
        System.Type objectType = typeof(T);
        System.Type parameterType = typeof(TParam);
        RefAction<object, object> ret;
        if (objectType.IsValueType)
        {
            RefAction<T, TParam> propertySetter = (RefAction<T, TParam>)System.Delegate.CreateDelegate(typeof(RefAction<T, TParam>), methodInfo);

            // we are trying to set some struct internal value.
            ret = (ref object target, object param) =>
            {
                T boxed = (T)target;
                propertySetter(ref boxed, (TParam)System.Convert.ChangeType(param, parameterType));
                target = boxed;
            };
        }
        else
        {
            System.Action<T, TParam> action = (System.Action<T, TParam>)System.Delegate.CreateDelegate(typeof(System.Action<T, TParam>), methodInfo);
            ret = (ref object target, object param) => action(target as T, (TParam)System.Convert.ChangeType(param, parameterType));
        }

        return ret;
    }

執行以下行時出現問題:

RefAction<T, TParam> propertySetter = (RefAction<T, TParam>)System.Delegate.CreateDelegate(typeof(RefAction<T, TParam>), methodInfo);

至少對我而言,這與上面鏈接帖子中使用的相同:

SomeMethodHandler d = (SomeMethodHandler)Delegate.CreateDelegate(typeof(SomeMethodHandler), method);

哪里:

delegate int SomeMethodHandler(ref A instance);
public struct A
{
    private int _Value;

    public int Value
    {
        get { return _Value; }
        set { _Value = value; }
    }

    private int SomeMethod()
    {
         return _Value;
    }
}

任何人都知道為什么它會在我身邊而不是在鏈接線程中產生異常? 它是否與C#運行時版本相關聯? 我正在努力團結,所以這是一個幾乎相當於3.5的單聲道框架......

無論如何,感謝閱讀,如果我在問題布局或語法中做錯了,請不要猶豫!

干杯,弗洛。

您正在創建靜態方法的委托而不是開放委托。 我在你的CreateDelegate調用中添加了null並且它有效(但我對性能不太確定,但是,使用雙重裝箱/取消裝箱):

public struct S
{
    public string Value {get; set;}
}

static class Program
{   

    public delegate void RefAction<T, TParam>(ref T arg, TParam param);
    static RefAction<object, object> ToOpenActionDelegate<T, TParam>(System.Reflection.MethodInfo methodInfo)
    {
        // Convert the slow MethodInfo into a fast, strongly typed, open delegate
        Type objectType = typeof(T);
        Type parameterType = typeof(TParam);
        RefAction<object, object> ret;
        if (objectType.IsValueType)
        {
            RefAction<T, TParam> propertySetter = (RefAction<T, TParam>)Delegate.CreateDelegate(typeof(RefAction<T, TParam>), null, methodInfo);

            // we are trying to set some struct internal value.
            ret = (ref object target, object param) =>
            {
                T boxed = (T)target;
                propertySetter(ref boxed, (TParam)System.Convert.ChangeType(param, parameterType));
                target = boxed;
            };
        }
        else
        {
            Action<T, TParam> action = (Action<T, TParam>)Delegate.CreateDelegate(typeof(Action<T, TParam>), null, methodInfo);
            ret = (ref object target, object param) => action((T)target, (TParam)System.Convert.ChangeType(param, parameterType));
        }

        return ret;
    }

    public static void Main(string[] args)
    {
        var s = new S();

        var mi = s.GetType().GetMethod("set_Value");
        /*
        var deleg = (RefAction<S, string>)Delegate.CreateDelegate(typeof(RefAction<S, string>), null, mi);

        deleg(ref s, "hello");

        RefAction<object, object> deleg2 = (ref object target, object param) => {
            S boxed = (S)target;
            deleg(ref boxed, (string)param);
            target = boxed;
        };
        */

        RefAction<object, object> deleg2 = ToOpenActionDelegate<S, string>(mi);

        var o = (object)s;

        deleg2(ref o, "world");

        s = (S)o;

        Console.WriteLine(s.Value); //prints "world"

        Console.ReadKey(true);
    }
}

暫無
暫無

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

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