C# - 如何获取复合对象的属性名称?



我有一个公司类,它有一个复合对象作为属性,该属性将公司对象作为其属性,依此类推。我需要用最少的代码在最深的级别获取属性的名称。

这是该案例的伪代码:

class Company
{
public Person Boss
{
public Document CV
{
public string Title;
}
}
}

我需要用尽可能少的代码获得"Company.Boss.CV.Title">的字符串结果。这样做的天真方法是尝试nameof(Company.Boss.CV.Title)但正如我们所知,这将只产生"标题"。

我需要使用类型而不是纯字符串,以允许编译器在有人更改属性名称时抛出错误。 显然是这样的:

string.Join('.', nameof(Company), nameof(Company.Boss), nameof(Company.Boss.CV), nameof(Company.Boss.CV.Title))

将在 100% 的时间内正常工作,但样板代码太多。任何建议都非常感谢!

您可以使用表达式并将其分解,如下所示:

Expression<Func<Company, object>> myExpr = (c) => c.Boss.CV.Title;
var expr = myExpr.Body;
var sb = new StringBuilder();
// Traverse the expression
while (expr != null)
{
switch (expr.NodeType){
case ExpressionType.MemberAccess:
var memberExpr = ((MemberExpression)expr);
sb.Insert(0, "." + memberExpr.Member.Name, 1);
expr = memberExpr.Expression;
break;
case ExpressionType.Parameter:
var paramExpr = ((ParameterExpression)expr);
parts.Add(paramExpr.Type.Name);
sb.Insert(0, paramExpr.Type.Name, 1);
expr = null;
break;
default:
expr = null;
break;
}
}
var propertyPath = sb.ToString(); // "Company.Boss.CV.Title"

使用 ExpressionVisitor

实现自定义 ExpressionVisitor 有助于使代码清晰。

public class MyExpressionVisitor : ExpressionVisitor{
private List<string> parts;
protected override Expression VisitMember(MemberExpression node)
{
parts.Add(node.Member.Name);
return base.VisitMember(node);
}
protected override Expression VisitParameter(ParameterExpression node)
{
parts.Add(node.Type.Name);
return base.VisitParameter(node);
}
public string GetPath(Expression e)
{
parts = new List<string>();
Visit(e is LambdaExpression ? ((LambdaExpression)e).Body : e);
parts.Reverse();
return string.Join(".", parts);
}
}

然后,您可以使用

Expression<Func<Company, object>> myExpr = (c) => c.Boss.CV.Title;
var myVisitor = new MyExpressionVisitor();
var propertyPath = myVisitor.GetPath(myExpr);

最新更新