您好,
我使用LINQ和EF与C#4.0。 口已经拖了基本表ELMAH到EF(建成并挽救了很多很多次)。 的所有工作正如人们所期望
但试图过于雄心勃勃,需要一些帮助 - 我想从获得列名。传递中作为变量表达式
我想是这样的:
在传递:X => x.ErrorId
和获取:ErrorID中
公共无效GetColumnName(表达式来; Func键< T,对象>>物业) { // x中传递的参数=> x.Message //消息使用正常工作(可能是因为它的一个简单的字符串)串COLUMNNAME =(property.Body为MemberExpression).Member.Name; //但是,如果我尝试使用GUID或日期字段则 //在为x =>通过; CONVERT(x.TimeUtc) //因此上面的代码生成一个例外NullReference //即{未将对象引用设置到对象的实例。} //什么是这里的正确的代码一般提取列名? //理想地在不会再次咬我在未来的一种方式。 }感谢您的帮助! 丹
解决方案如果您还需要分解简(或几乎简单)的表达式,你需要一些额外的跑腿来处理不同的情况。这里是处理一些常见的情况下,一些启动代码:
字符串GetColumnName< T,TResult>(表达式来; Func键< T,TResult> ;>物业) { VAR成员= GetMemberExpression(property.Body); 如果(成员== NULL)抛出新的ArgumentException(不能还原为一个成员访问,财产); 返回member.Member.Name; } MemberExpression GetMemberExpression(表达式体) {变种候选人=新的问答LT;表达>(); candidates.Enqueue(体); ,而(candidates.Count大于0) { VAR EXPR = candidates.Dequeue(); 如果(表达式为MemberExpression) {回报率((MemberExpression)表达式); } ,否则如果(表达式为UnaryExpression) { candidates.Enqueue(((UnaryExpression)表达式).Operand); } ,否则如果(表达式是BinaryExpression) { VAR二进制= EXPR为BinaryExpression; candidates.Enqueue(binary.Left); candidates.Enqueue(binary.Right); } ,否则如果(表达式为MethodCallExpression) { VAR方法= EXPR为MethodCallExpression; 的foreach(在method.Arguments VAR参数) { candidates.Enqueue(参数); } } ,否则如果(表达式为LambdaExpression) { candidates.Enqueue(((LambdaExpression)表达式)。体); } } 返回NULL; }
这产生输出,如:
GetColumnName((X)=> XX):X GetColumnName((X)=> XX + 2):X GetColumnName((X)=→2 + XX):X GetColumnName((X)=> -XX):X GetColumnName((X)=>数学。 SQRT(XY)):Y GetColumnName((X)=>的Math.sqrt(Math.Abs(XY))):Y
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 expression 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"
更多推荐
LINQ成员表达越来越列名
发布评论