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; }
[JsonProperty("hobbies")]
public List<string> Hobbies { 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; }
[JsonProperty("activities")]
public List<WorkActivity> WorkActivities { get; set; }
}
public class WorkActivity
{
[JsonProperty("id")]
public int Id { get; set; }
[JsonProperty("rooms")]
public List<string> Rooms { get; set; }
}
I have the following classes:
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);
}
}
And I call it like this:
private static List<string> FindPropertyNames<T>(Expression<Func<T, object>> e)
{
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.Age, x.Country, x.Profession.AverageSalary, x.Hobbies });
Console.WriteLine(string.Join(" ", names));
}
It works fine, except for one minor detailed - it doesn't check for nested properties. The output is the following: age country profession hobbies
. I want it to be age country profession.salary hobbies
.
I've been trying to fix the issue using a different approach, but I am unable to do so fully. I've tried the following:
public static MemberExpression GetMemberExpression(Expression e)
{
if (e is MemberExpression)
{
return (MemberExpression)e;
}
else if (e is LambdaExpression)
{
var le = e as LambdaExpression;
if (le.Body is MemberExpression)
{
return (MemberExpression)le.Body;
}
else if (le.Body is UnaryExpression)
{
return (MemberExpression)((UnaryExpression)le.Body).Operand;
}
}
return null;
}
public static string GetPropertyPath<T>(Expression<Func<T, object>> expr)
{
var path = new StringBuilder();
MemberExpression me = GetMemberExpression(expr);
do
{
if (path.Length > 0)
{
path.Insert(0, ".");
}
path.Insert(0, me.Member.GetCustomAttribute<JsonPropertyAttribute>().PropertyName);
me = GetMemberExpression(me.Expression);
}
while (me != null);
return path.ToString();
}
It kind of does the job - but it can't take more than one property.
I call it like this:
var x = GetPropertyPath<Person>(p => p.Profession.AverageSalary);
Console.WriteLine(x);
I want to be able to send multiple properties, as in the first version. Also, I am unsure how to pass the following person.Profession.WorkActivities.Rooms
as a parameter, because it is a list. I want to get profession.activities.rooms
as output for it.
Aucun commentaire:
Enregistrer un commentaire