开发者

LINQ member expression getting column name

Hello,

I am using LINQ and EF with C# 4.0. I have dragged the basic ELMAH table into EF (built and saved many many times). All is working as one would expect.

But have tried to be too ambitious and need a little help - I am trying to get the Column name from an expressi开发者_运维问答on that is passed in as a variable.

What I want is this:

Pass in : x=>x.ErrorId

and get : "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.

}

Thank you for your help! Dan.


If you need to also decompose simple (or nearly simple) expressions, you'll need some extra legwork to handle the different situations. Here is some starter code that handles some common cases:

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;
}

Which produces output like:

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"
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜