lundi 7 juin 2021

Using Expression to access strongly typed nested properties

I have the following classes:

public class Person
{
    [JsonProperty("name")]
    public string Name { get; set; }

    [JsonProperty("age")]
    public int Age { get; set; }

    [JsonProperty("country")]
    public string Country { get; set; }

    [JsonProperty("profession")]
    public Profession Profession { get; set; }
}

public class Profession
{
    [JsonProperty("name")]
    public string ProfessionName { get; set; }

    [JsonProperty("industry")]
    public string Industry { get; set; }

    [JsonProperty("salary")]
    public string AverageSalary { get; set; }
}

I have the following ExpressionVisitor:

public class PropertiesVisitor : ExpressionVisitor
{
    private readonly Expression param;

    public List<string> Names { get; } = new List<string>();

    public PropertiesVisitor(Expression parameter)
    {
        param = parameter;
    }

    protected override Expression VisitMember(MemberExpression node)
    {
        if (node.Expression == param)
        {
            Names.Add(node.Member.GetCustomAttribute<JsonPropertyAttribute>().PropertyName);
        }

        return base.VisitMember(node);
    }
}

I do the following inside my app:

private static List<string> FindPropertyNames<T>(Expression<Func<T, object>> e)
{
    if (e == null)
    {
        return new List<string>();
    }

    var visitor = new PropertiesVisitor(e.Parameters[0]);
    visitor.Visit(e);
    return visitor.Names;
}

public static void Main(string[] args)
{
    var names = FindPropertyNames<Person>(x => new { x.Name, x.Age, x.Profession.AverageSalary });

    Console.WriteLine(string.Join(" ", names));
}

And it works almost perfectly. For normal properties (not nested) it returns the correct results, however, for nested properties, it doesn't work as intended.

The output is: name age profession

The desired output is name age profession.salary.





Aucun commentaire:

Enregistrer un commentaire