简体   繁体   中英

C# Expression tree for string interpolation

I have a program that reads a json file with some property names of a certain class. The values of the configured property names should compose up a key.

Lets take an example:

Class:

class SomeClass
{
    public string PropertyOne { get; set; }
    public string PropertyTwo { get; set; }
    public string PropertyThree { get; set; }
    public string PropertyFour { get; set; }
}

var someClass = new SomeClass
            {
                PropertyOne = "Value1",
                PropertyTwo = "Value2",
                PropertyThree = "Value3",
                PropertyFour = "Value4",
            };

Configuration file:

{
   "Properties": ["PropertyOne", "PropertyTwo"]
}

If I knew the properties at compile time I would have create a lambda like:

Func<SomeClass, string> keyFactory = x => $"{x.PropertyOne}|{x.PropertoTwo}"

Is there a way to compile such a lambda using expressions? Or any other suggestions maybe?

In Expression Tree, string interpolation is converted to string.Format . Analogue of your sample will be:

Func<SomeClass, string> keyFactory = 
   x => string.Format("{0}|{1}", x.PropertyOne, x.PropertoTwo);

The following function created such delegate dynamically:

private static MethodInfo _fromatMethodInfo = typeof(string).GetMethod(nameof(string.Format), new Type[] { typeof(string), typeof(object[]) });

public static Func<T, string> GenerateKeyFactory<T>(IEnumerable<string> propertyNames)
{
    var entityParam = Expression.Parameter(typeof(T), "e");

    var args = propertyNames.Select(p => (Expression)Expression.PropertyOrField(entityParam, p))
            .ToList();

    var formatStr = string.Join('|', args.Select((_, idx) => $"{{{idx}}}"));

    var argsParam = Expression.NewArrayInit(typeof(object), args);

    var body = Expression.Call(_fromatMethodInfo, Expression.Constant(formatStr), argsParam);
    var lambda = Expression.Lambda<Func<T, string>>(body, entityParam);
    var compiled = lambda.Compile();

    return compiled;
}

Usage:

var keyFactory = GenerateKeyFactory<SomeClass>(new[] { "PropertyOne", "PropertyTwo", "PropertyThree" });

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM