C# LINQ - selecting a dynamic object based on properties defined at runtime

c# dynamic entity-framework-core expression-trees linq

Question

I've been attempting to develop an expression that can transform a strongly typed EF Core entity into a dynamic object with a list that is runtime created through a REST API query.

I currently have the following:

Expression<Func<Message, dynamic>> DynamicFields(IEnumerable<string> fields)
{
    var xParameter = Expression.Parameter(typeof(Message), "o");
    var xNew = Expression.New(typeof(ExpandoObject));

    var bindings = fields.Select(o => {
        var mi = typeof(Message).GetProperty(o);
        var xOriginal = Expression.Property(xParameter, mi);
        return Expression.Bind(mi, xOriginal);
    });

    var xInit = Expression.MemberInit((dynamic)xNew, bindings);

    return Expression.Lambda<Func<Message, dynamic>>(xInit, xParameter);
}

Even though it seems like I'm very near, this fails at runtime with the error "X property is not a member of ExpandoObject." I've tried adjusting how dynamic and ExpandoObject are used, but nothing appears to work. Is this even doable?

When I substitute Message for dynamic or expandoObject, everything still functions as intended, but an instance of the Message class is returned with all of its attributes set to their default settings.

Has anyone tried this before?

Cheers.

1
1
9/7/2018 7:13:55 PM

Popular Answer

There is no way to project toExpandoObject / dynamic directly.

But at runtime, you may project to types that were formed dynamically. Consider the Microsoft.EntityFrameworkCore.DynamicLinq package and Interactive Data Classes, for example.

The method in question may be implemented as follows if you install the package from nuget (you can create equivalent functionality on your own, but you should essentially implement what that section of the package is doing):

using System.Linq.Dynamic.Core;

static Expression<Func<TSource, dynamic>> DynamicFields<TSource>(IEnumerable<string> fields)
{
    var source = Expression.Parameter(typeof(TSource), "o");
    var properties = fields
        .Select(f => typeof(TSource).GetProperty(f))
        .Select(p => new DynamicProperty(p.Name, p.PropertyType))
        .ToList();
    var resultType = DynamicClassFactory.CreateType(properties, false);
    var bindings = properties.Select(p => Expression.Bind(resultType.GetProperty(p.Name), Expression.Property(source, p.Name)));
    var result = Expression.MemberInit(Expression.New(resultType), bindings);
    return Expression.Lambda<Func<TSource, dynamic>>(result, source);
}
2
9/7/2018 7:12:47 PM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow