none
ConstantExpressionから変数の値を取得したい RRS feed

  • 質問


  • 			var point=new Point(1,2);
    			Expression<Func<int>> lambda2=() => point.Y;
    			var M=lambda2.Body as MemberExpression;
    			//何とかしてMからpoint.Yの値 2を取得したい
    
    やりたいことは式木(Expression)を走査して変数やメンバ変数の値を取得したいのです。
    デバッガでウオッチ式を見ると確かに何らかの形で値が見れるのですがどうコードを書いていいかわかりません。
    取得する方法がわかればご教授お願いしたいです。
    2009年6月6日 5:00

回答

  • var point = new Point( 1, 2 );
    Expression<Func<int>> lambda = () => point.Y;

    // lambda式は
    var bodyExpression = lambda.Body as MemberExpression;
    // 「point」式と
    var pointExpression = bodyExpression.Expression as MemberExpression;
    // Point.Yプロパティアクセス
    var propertyY = bodyExpression.Member as PropertyInfo;
    // 「point」式はlambda式の入力となっている定数のうち
    var constantExpression = pointExpression.Expression as ConstantExpression;
    // 「point」という名前を持っている
    var fieldPoint = pointExpression.Member as FieldInfo;

    var valuePoint = (Point)fieldPoint.GetValue( constantExpression.Value );
    var valueY = (int)propertyY.GetValue( valuePoint, null );
    Console.WriteLine( valueY );


    うーん、わかってはいたけど、大変ですね(^^;
    • 回答としてマーク 和和和 2009年6月8日 0:36
    2009年6月6日 6:16
  • これは長い間悩んでいたものを解決してくださりありがとうございました。
    これを参考にして深いオブジェクトの参照も取得できるようにしてみました。
    		private static Object オブジェクト取得(MemberExpression MemberExpression,PropertyInfo PropertyInfo) {
    			return PropertyInfo.GetValue(オブジェクト取得(MemberExpression),null);
    		}
    		private static Object オブジェクト取得(MemberExpression MemberExpression) {
    			var MemberExpression_Expression=MemberExpression.Expression;
    			if(MemberExpression_Expression.NodeType==ExpressionType.MemberAccess) {
    				return オブジェクト取得(MemberExpression_Expression as MemberExpression,MemberExpression.Member as PropertyInfo);
    			} else {
    				var Constant=MemberExpression_Expression as ConstantExpression;
    				var FieldInfo=MemberExpression.Member as FieldInfo;
    				return FieldInfo.GetValue(Constant.Value);
    			}
    		}
    		public class Point2{
    			private Point1 _Point1=new Point1();
    			public Point1 Point1 {
    				get {
    					return this._Point1;
    				}
    			}
    		}
    		public class Point1 {
    			private Point _Point0=new Point(3,4);
    			public Point Point0 {
    				get {
    					return this._Point0;
    				}
    			}
    		}
    		private void Form1_Load(object sender,EventArgs e) {
    			var 変数=5;
    			var point0=new Point(1,2);
    			var point1=new Point1();
    			var point2=new Point2();
    			Expression<Func<int>> lambda=() => 変数;
    			Expression<Func<int>> lambda0=() => point0.X;
    			Expression<Func<int>> lambda1=() => point1.Point0.X;
    			Expression<Func<int>> lambda2=() => point2.Point1.Point0.X;
    			var 変数値=オブジェクト取得(lambda.Body as MemberExpression);
    			var point0値=オブジェクト取得(lambda0.Body as MemberExpression);
    			var point1値=オブジェクト取得(lambda1.Body as MemberExpression);
    			var point2値=オブジェクト取得(lambda2.Body as MemberExpression);
                    }
    自分でLINQ to SQL作ってみたいんで通常の四則演算や関数やLINQ to Objectを実行時に定数化してクエリ式に渡したいのがそもそもの目的でした。
    • 回答としてマーク 和和和 2009年6月8日 0:36
    2009年6月7日 5:23

すべての返信

  • var point = new Point( 1, 2 );
    Expression<Func<int>> lambda = () => point.Y;

    // lambda式は
    var bodyExpression = lambda.Body as MemberExpression;
    // 「point」式と
    var pointExpression = bodyExpression.Expression as MemberExpression;
    // Point.Yプロパティアクセス
    var propertyY = bodyExpression.Member as PropertyInfo;
    // 「point」式はlambda式の入力となっている定数のうち
    var constantExpression = pointExpression.Expression as ConstantExpression;
    // 「point」という名前を持っている
    var fieldPoint = pointExpression.Member as FieldInfo;

    var valuePoint = (Point)fieldPoint.GetValue( constantExpression.Value );
    var valueY = (int)propertyY.GetValue( valuePoint, null );
    Console.WriteLine( valueY );


    うーん、わかってはいたけど、大変ですね(^^;
    • 回答としてマーク 和和和 2009年6月8日 0:36
    2009年6月6日 6:16
  • これは長い間悩んでいたものを解決してくださりありがとうございました。
    これを参考にして深いオブジェクトの参照も取得できるようにしてみました。
    		private static Object オブジェクト取得(MemberExpression MemberExpression,PropertyInfo PropertyInfo) {
    			return PropertyInfo.GetValue(オブジェクト取得(MemberExpression),null);
    		}
    		private static Object オブジェクト取得(MemberExpression MemberExpression) {
    			var MemberExpression_Expression=MemberExpression.Expression;
    			if(MemberExpression_Expression.NodeType==ExpressionType.MemberAccess) {
    				return オブジェクト取得(MemberExpression_Expression as MemberExpression,MemberExpression.Member as PropertyInfo);
    			} else {
    				var Constant=MemberExpression_Expression as ConstantExpression;
    				var FieldInfo=MemberExpression.Member as FieldInfo;
    				return FieldInfo.GetValue(Constant.Value);
    			}
    		}
    		public class Point2{
    			private Point1 _Point1=new Point1();
    			public Point1 Point1 {
    				get {
    					return this._Point1;
    				}
    			}
    		}
    		public class Point1 {
    			private Point _Point0=new Point(3,4);
    			public Point Point0 {
    				get {
    					return this._Point0;
    				}
    			}
    		}
    		private void Form1_Load(object sender,EventArgs e) {
    			var 変数=5;
    			var point0=new Point(1,2);
    			var point1=new Point1();
    			var point2=new Point2();
    			Expression<Func<int>> lambda=() => 変数;
    			Expression<Func<int>> lambda0=() => point0.X;
    			Expression<Func<int>> lambda1=() => point1.Point0.X;
    			Expression<Func<int>> lambda2=() => point2.Point1.Point0.X;
    			var 変数値=オブジェクト取得(lambda.Body as MemberExpression);
    			var point0値=オブジェクト取得(lambda0.Body as MemberExpression);
    			var point1値=オブジェクト取得(lambda1.Body as MemberExpression);
    			var point2値=オブジェクト取得(lambda2.Body as MemberExpression);
                    }
    自分でLINQ to SQL作ってみたいんで通常の四則演算や関数やLINQ to Objectを実行時に定数化してクエリ式に渡したいのがそもそもの目的でした。
    • 回答としてマーク 和和和 2009年6月8日 0:36
    2009年6月7日 5:23