您好
我正在使用LINQ和EF和C#4.0。 我已将基本的ELMAH表拖入EF(已构建并保存了很多次)。 一切都按照人们的预期运作。
但是他们试图过于雄心勃勃并需要一些帮助 - 我试图从一个作为变量传入的表达式中获取Column名称。
我想要的是:
传入:x => x.ErrorId
并获取:“ErrorId”
public void GetColumnName(Expression<Func<T, object>> property)
{
// The parameter passed in x=>x.Message
// Message works fine (probably because its a simple string) using:
string columnName = (property.Body as MemberExpression).Member.Name;
// But if I attempt to use the Guid or the date field then it
// is passed in as x => Convert(x.TimeUtc)
// As a result the above code generates a NullReference exception
// i.e. {"Object reference not set to an instance of an object."}
// What is the correct code here to extract the column name generically?
// Ideally in a way that won't bite me again in the future.
}
感谢您的帮助! 丹。
答案 0 :(得分:6)
如果你还需要分解简单(或接近简单)的表达式,你需要一些额外的工作来处理不同的情况。以下是一些处理一些常见情况的入门代码:
string GetColumnName<T,TResult>(Expression<Func<T,TResult>> property)
{
var member = GetMemberExpression(property.Body);
if (member == null)
throw new ArgumentException("Not reducible to a Member Access",
"property");
return member.Member.Name;
}
MemberExpression GetMemberExpression(Expression body)
{
var candidates = new Queue<Expression>();
candidates.Enqueue(body);
while (candidates.Count > 0)
{
var expr = candidates.Dequeue();
if (expr is MemberExpression)
{
return ((MemberExpression)expr);
}
else if (expr is UnaryExpression)
{
candidates.Enqueue(((UnaryExpression)expr).Operand);
}
else if (expr is BinaryExpression)
{
var binary = expr as BinaryExpression;
candidates.Enqueue(binary.Left);
candidates.Enqueue(binary.Right);
}
else if (expr is MethodCallExpression)
{
var method = expr as MethodCallExpression;
foreach (var argument in method.Arguments)
{
candidates.Enqueue(argument);
}
}
else if (expr is LambdaExpression)
{
candidates.Enqueue(((LambdaExpression)expr).Body);
}
}
return null;
}
产生的输出如下:
GetColumnName((x) => x.X): "X"
GetColumnName((x) => x.X + 2): "X"
GetColumnName((x) => 2 + x.X): "X"
GetColumnName((x) => -x.X): "X"
GetColumnName((x) => Math.Sqrt(x.Y)): "Y"
GetColumnName((x) => Math.Sqrt(Math.Abs(x.Y))): "Y"