如何编写一个带有一个参数的委托?

时间:2016-06-02 15:01:45

标签: c# .net reflection

我正在摆弄已编译的委托,并尝试使用编译委托调用以下类中的SerializeDeserialize函数(不要介意名称)。我成功地拨打了Serialize,但没有Deserialize。问题似乎是我似乎不明白如何将string参数传递给以下代码中的Func对象。有没有人知道我的代码(和大脑)的修复?

public class SomeClass
{
    public string SomeString { get; }

    public SomeClass(string str)
    {
        SomeString = str;
    }


    public string Serialize()
    {
        return SomeString;
    }


    public SomeClass Deserialize(string str)
    {
        return new SomeClass(str + " - !!!!");
    }
}

public class Program
{
    private static class TypeSerializationCache<T>
    {
        public static readonly Func<T, string> Serialize;
        public static readonly Func<string, T> DeserializeThatShouldBe;
        public static readonly Func<T, string, T> DeserializeOriginalFixed;

        static TypeSerializationCache()
        {

            const string SerializeFunctionToCall = "Serialize";
            var serializeFuncParameterValue = Expression.Parameter(typeof(T), "serializeFuncParameterValue");
            var serializeMethod = typeof(T).GetMethod(SerializeFunctionToCall, BindingFlags.Instance | BindingFlags.Public, null, new Type[] { }, null);

            var serializeCall = serializeMethod != null ? (Expression)Expression.Call(serializeFuncParameterValue, serializeMethod) : Expression.Constant(default(T), typeof(T));
            Serialize = Expression.Lambda<Func<T, string>>(serializeCall, serializeFuncParameterValue).Compile();


            const string DeserializeCallFunction = "Deserialize";
            var deserializeFuncParameterValue = Expression.Parameter(typeof(T), "DeserializeFuncParameterValue");                
            var deserializeMethod = typeof(T).GetMethod(DeserializeCallFunction, BindingFlags.Instance | BindingFlags.Public, null, new Type[] { typeof(string) }, null);
            var deserializeArgument = Expression.Parameter(typeof(string), "deserializeArgument");

            var deserializeCall = Expression.Call(deserializeFuncParameterValue, deserializeMethod, deserializeArgument);

             DeserializeOriginalFixed = Expression.Lambda<Func<T, string, T>>(deserializeCall, deserializeFuncParameterValue, deserializeArgument).Compile();

             //To my great dismay, the following throws.
             DeserializeThatShouldBe = Expression.Lambda<Func<string, T>>(deserializeCall, deserializeFuncParameterValue, deserializeArgument).Compile();

        }
    }

    public static void Main(string[] args)
    {            
        var class11 = new SomeClass("XYZ");
        var class12 = new SomeClass("123");

        var class31 = TypeSerializationCache<SomeClass>.Serialize(class11);
        var class32 = TypeSerializationCache<SomeClass>.Serialize(class12);
        var class31d = TypeSerializationCache<SomeClass>.DeserializeOriginalFixed(class11, class31);
        var class32d = TypeSerializationCache<SomeClass>.DeserializeThatShouldBe(class32);
    }

&lt; edit:我需要回来(清醒)并尝试修复参数的数量。不是我希望的,理想情况下我只想使用type参数和序列化字符串。此外, duck talk 让我想起了bug talk。 :)

Aanyway,我仍然在寻找根本修复,而不仅仅是创可贴......

&lt; edit 2:现在,root修复程序似乎在我的大脑中,并且理解一个实例方法或静态方法需要一个实例。我想我的鸭子排成一排并计算好后闭嘴。我要感谢 Eric

1 个答案:

答案 0 :(得分:9)

  

有没有人知道我的代码修复

向程序员展示错误,他们修复了错误。 教会程序员如何找到错误,并停止发布他们的错误代码供其他人调试,节省每个人的时间。

获得一只橡皮鸭。请大声读出大声这一行。

var deserializeFuncParameterValue = Expression.Parameter(typeof(T), "DeserializeFuncParameterValue");                

现在快速阅读大声这一行。

Deserialize = Expression.Lambda<Func<string, T>>(deserializeCall, deserializeFuncParameterValue, deserializeArgument).Compile();

现在向鸭子解释鸭子完全不知道表达树为什么代码是正确的。由于代码正确,您应该无法执行此操作。您无法执行此操作的具体点是错误,或者是您无法证明正确代码的点。无论哪种方式,你已经学到了一些关于代码的东西,可能你已经找到了这个bug。

提示:错误消息没有错误。如果需要,也请向鸭子大声朗读错误信息。

(原始海报忽略了发布错误消息,即“为lambda声明提供的参数数量不正确”。)

  

(和大脑)?

橡皮鸭调试是有效的,因为它可以阻止你发现这个错误。你的大脑想要相信你写的代码是正确的,它实际上不允许你看到明显的问题。你读了代码,你的眼睛釉了一下,这“显然是正确的”。不,不是。

向鸭子解释它会迫使你的大脑重新检查错误的假设,这些假设会让你相信错误的代码“显然是正确的”。

请注意it works for mechanical engineering problems and stuffed ducks too