samedi 12 janvier 2019

How do I construct and compile this C# Expression with Generic types & lambda

I am trying to create a custom serializer. It needs to be performant.

The idea is to construct and cache some Func<…> for each type

In this simplified example, I successfully construct the Func for STRING types, but I'm stuck on how to construct it for ARRAY types.

It could be helpful to imagine that I can now serialize the Meow class, but that I would fail to serialize the Ruff class.

class Meow
{
    public string Rawr { get; set; }
}
class Ruff
{
    public Meow[] Grr { get; set; }
}
static class Serializer<T>
{
    static bool DoSomething(string value, Stream stream) => true;
    static bool DoSomethingElse(T[] values, Stream stream) => true;

    public static Func<T, Stream, bool> GetSerializer()
    {
        var firstProperty = typeof(T).GetProperties()[0].GetGetMethod();

        var typeParam = Expression.Parameter(typeof(T));
        var compiledGetter = Expression
            .Lambda(
                Expression.Call(firstProperty, typeParam),
                typeParam
            )
            .Compile();

        var returnType = firstProperty.ReturnType;

        if (returnType == typeof(string))
        {
            var getString = (Func<T, string>)compiledGetter;
            return (T item, Stream stream) => DoSomething(getString(item), stream);
        }
        if (returnType.IsArray)
        {
            // var getArray = (Func<T, returnType>)compiledGetter;

            var elementType = returnType.GetElementType();

            // return (T item, Stream stream) => 
            //    Serializer<elementType>.DoSomethingElse(getArray(item), stream))
        }
        return null;
    }
}

Serializing Meow is easy. The function will take the T and Stream, extract string from T, and pass them into DoSomething(string, Stream) to return a bool.

But while serializing Ruff, it encounters a property with return type Meow[]. To serialize it, it needs to take T and Stream, extract an array of an unknown element type from T, and pass them into Serializer<Meow>.DoSomethingElse(Meow[], Stream)

The commented-out lines show the gist of what I think needs to happen. But how can I create a compiled Expression for it all and finally return a Func<T, Stream, bool>?





Aucun commentaire:

Enregistrer un commentaire