Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

184
Visualizações
Expression tree to create lambda for generating a c# dictionary

I have a stream of thousands of data which I need to transform and add to a list. The transformation happens through the reflection similar to following

_myObservable.Subscribe(d => {
    PropertyInfo[] props = d.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public);
    var propValDict = props.ToDictionary(prop => prop.Name, prop => prop.GetValue(d, null));
    myList.Add(propValDict);
});

// Datatype of d is determined during runtime and there are only 8 possibilities of the type

But this approach is slowing down the performance and I expect the use of reflection might be the reason. I am thinking of improving the performance by some other means.

Suggestions seem to point at use of Expression trees, create compiled lambda (Func<object,Dictionary<string, object>>) and store it in a lookup dictionary before hand.

//Foreach possibleType in PossibleTypes, Do below

PropertyInfo[] props = possibleType.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public);

var rootParam = Expression.Parameter(typeof(object), "d");
var param = Expression.Parameter(typeof(PropertyInfo), "prop");
var propertyFirst = Expression.Property(param, "Name");

var param2 = Expression.Parameter(typeof(PropertyInfo), "prop");
var callMethod = Expression.Call(param2, typeof(PropertyInfo).GetMethod(nameof(PropertyInfo.GetValue), new Type[] { typeof(object) }), rootParam);

var pro = Expression.Parameter(typeof(Array), "props");

var toDict = Expression.Invoke(pro, propertyFirst, callMethod);
var lambda = Expression.Lambda<Func<object, Dictionary<string, object>>>(toDict, rootParam);
var compiled = lambda.Compile();

I am having trouble to invoke ToDictionary of Enumerable class There is something which I am missing with this approach or Will this really improve performance.

Please help...

over 4 years ago · Santiago Trujillo
1 Respostas
Responde à pergunta

0

When thinking with expressions, you always need to figure out what the equivalent C# code would look like. In this case, the equivalent C# code wouldn't be looping over a collection of PropertyInfo, instead it would probably look like:

public static Func<object, Dictionary<string, object>> CreateConvertToPropertyDict<T>()
{
    return input =>
    {
        var d = (T)input;
        return new Dictionary<string, object>())
        {
            { "Foo", d.Foo },
            { "Bar", d.Bar },
        };
    };
}
myList.Add(propValDict);

Move sidewards in the land of expressions, and you end up with something like:

public static Func<object, Dictionary<string, object>> CreatePropertyDict(Type type)
{
    // Consider caching these in a static field, since they're constant
    var dictType = typeof(Dictionary<string, object>);
    var dictCtor = dictType.GetConstructor(new[] { typeof(int) });
    var dictAddMethod = dictType.GetMethod("Add");

    var properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public);
    
    var blockExpressions = new List<Expression>();
    
    // 'object input' is our input parameter
    var inputParameter = Expression.Parameter(typeof(object), "input");
    // MyType d;
    var dVariable = Expression.Variable(type, "d");
    // d = (MyType)inputObject;
    blockExpressions.Add(Expression.Assign(dVariable, Expression.Convert(inputParameter, type)));
    // Dictionary<string, object> dict;
    var dictVariable = Expression.Variable(dictType, "dict");
    // dict = new Dictionary<string, object>(3) (or however many properties there are)
    blockExpressions.Add(Expression.Assign(dictVariable, Expression.New(dictCtor, Expression.Constant(properties.Length))));
    
    foreach (var property in properties)
    {
        var propertyAccess = Expression.Property(dVariable, property);
        // dict.Add("Foo", (object)d.Foo)
        blockExpressions.Add(Expression.Call(
            dictVariable,
            dictAddMethod,
            Expression.Constant(property.Name),
            Expression.Convert(propertyAccess, typeof(object))));
    };
    
    // The final statement in a block is the return value
    blockExpressions.Add(dictVariable);
    
    var block = Expression.Block(new[] { dVariable, dictVariable }, blockExpressions);
    return Expression.Lambda<Func<object, Dictionary<string, object>>>(block, inputParameter).Compile();
}

With the simple test case:

public static void Main()
{
    var test = new Test() { Foo = "woop", Bar = 3 };
    var expr = CreatePropertyDict(typeof(Test));
    expr(test).Dump();
}

See it on dotnetfiddle.

There are several more advanced usages of Expression here, and I'm not going to go into the detail of each one. Look at the docs, and have a play around with the sorts of expressions that the C# compiler generates for different bits of C# code.

over 4 years ago · Santiago Trujillo Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda