我想做的事情可能有点奇怪。 但是我正在尝试(这是我能解释的最好的)使用反射将完整的类属性树名称作为字符串。
到目前为止成功范例:
通过使用我能够转换的表达式:
() => Model.Cargo.Id
进入字符串:
"Model.Cargo.Id"
我现在的问题是当我在混合中使用数组时,我没有得到数组名称。我得到的只是最后一个属性名称。
不成功的例子:
Model.CargoTasks[j].IsSet
只返回字符串:
"IsSet"
理想情况我想要以下字符串结果:
"Model.CargoTasks[0].IsSet"
我可能要求在结果中包含索引,但如果可能的话,这将是幻想。
我正在使用的代码来处理这些示例如下:
public static string ToMemberAccess<TResult>(this Expression<Func<TResult>> expression)
{
// Get the body of the expression
Expression body = expression.Body;
if (body.NodeType != ExpressionType.MemberAccess && body.NodeType != ExpressionType.Convert)
{
throw new ArgumentException("Property expression must be of the form '() => SomeProperty'", "expression");
}
var memberExpression = expression.Body as MemberExpression ?? ((UnaryExpression)expression.Body).Operand as MemberExpression;
var stuff = GetMemberNames(memberExpression);
stuff.Reverse();
return string.Join(".", stuff);
}
static List<string> GetMemberNames(MemberExpression expression, List<string> actual = null)
{
if (actual == null) actual = new List<string>();
var member = expression.Member;
var subExp = expression.Expression as MemberExpression;
actual.Add(member.Name);
if(subExp != null) actual = GetMemberNames(subExp, actual);
return actual;
}
事先谢谢!任何帮助将不胜感激!
答案 0 :(得分:0)
要获取索引器中的值,您必须编译并执行表达式 - 过于昂贵,但可以使用ExpressionStringBuilder
的修改版本来完成。请注意,我添加了一个参数compileConstants
。当它设置为false
时,输出将类似于Model.CargoTasks[_.j].IsSet
。
请注意,此示例访问者不完整(即它不支持所有类型的表达式)。您可以使用code in GitHub补充它。
public static string ToMemberAccess<TResult>(Expression<Func<TResult>> expression, bool compileConstants = false)
{
var builder = new ExpressionStringBuilder(compileConstants);
builder.Visit(expression);
return builder.ToString();
}
internal class ExpressionStringBuilder : ExpressionVisitor
{
private readonly bool _compileConstants;
private readonly StringBuilder _out;
public ExpressionStringBuilder(bool compileConstants)
{
_compileConstants = compileConstants;
_out = new StringBuilder();
}
protected override Expression VisitConstant(ConstantExpression node)
{
if (node.Value != null)
{
string text = node.Value.ToString();
if (node.Value is string)
{
Out("\"");
Out(text);
Out("\"");
}
else if (text == node.Value.GetType().ToString())
{
Out('_');
}
else
{
Out(text);
}
}
else
{
Out("null");
}
return node;
}
protected override Expression VisitMethodCall(MethodCallExpression node)
{
int num = 0;
Expression expression = node.Object;
if (Attribute.GetCustomAttribute(node.Method, typeof(ExtensionAttribute)) != null)
{
num = 1;
expression = node.Arguments[0];
}
var name = node.Method.Name;
var isIndexer = name == "get_Item";
if (expression != null)
{
Visit(expression);
if (!isIndexer)
{
Out('.');
}
}
if (isIndexer)
Out('[');
else
{
Out(name);
Out('(');
}
int i = num;
int count = node.Arguments.Count;
while (i < count)
{
if (i > num)
{
Out(", ");
}
VisitArgument(node.Arguments[i]);
i++;
}
Out(isIndexer ? ']' : ')');
return node;
}
protected override Expression VisitIndex(IndexExpression node)
{
if (node.Object != null)
{
Visit(node.Object);
}
else
{
Out(node.Indexer.DeclaringType.Name);
}
if (node.Indexer != null)
{
Out(".");
Out(node.Indexer.Name);
}
Out('[');
for (var index = 0; index < node.Arguments.Count; index++)
{
if (index > 0)
{
Out(", ");
}
var expression = node.Arguments[index];
VisitArgument(expression);
}
Out(']');
return node;
}
protected override Expression VisitLambda<T>(Expression<T> node)
{
Visit(node.Body);
return node;
}
protected override Expression VisitMember(MemberExpression node)
{
OutMember(node.Expression, node.Member);
return node;
}
public override string ToString()
{
return _out.ToString();
}
private void VisitArgument(Expression expression)
{
if (_compileConstants)
{
// TODO: possibly check the expression is not dependent on parameters
var value = Expression.Lambda(expression).Compile().DynamicInvoke();
Out(value + string.Empty);
}
else
{
VisitArgument(expression);
}
}
private void OutMember(Expression instance, MemberInfo member)
{
if (instance != null)
{
Visit(instance);
if (_out.Length > 0)
Out('.');
Out(member.Name);
return;
}
Out(member.DeclaringType.Name + "." + member.Name);
}
private void Out(char c)
{
_out.Append(c);
}
private void Out(string s)
{
_out.Append(s);
}
}