jeudi 2 juin 2016

How to compile a delegate taking one argument?

I was fiddling with compiled delegates and tried to call Serialize and Deserialize functions in the following class using compile delegates (don't mind the names). I had success in calling Serialize, but not Deserialize. The problem seem to be I don't seem to understand how to pass the string argument to the Func object in the following code. Does anyone know a fix to my code (and brain)?

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> Deserialize;

        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);

             //To my great dismay, the following throws.
             Deserialize = 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>.Deserialize(class31);
        var class32d = TypeSerializationCache<SomeClass>.Deserialize(class32);
    }





Aucun commentaire:

Enregistrer un commentaire