I. Getting started with expression trees
The lambda expression tree is complex and conceptually difficult to understand, in a word, the expression tree is a data structure! Here we use the following example to understand the expression tree, you can see a general:
Dynamic creation method for lambda expression tree
Static voidMain (string[] args) { //i*j+w*xParameterExpression A = Expression.parameter (typeof(int),"I");//Create a parameter in an expression tree, as a node, this is the lowest nodeParameterExpression B = Expression.parameter (typeof(int),"J"); Binaryexpression R1= Expression.multiply (A, b);//here i*j, generate a node in the expression tree, one level higher than the above nodeparameterexpression C= Expression.parameter (typeof(int),"W"); ParameterExpression D= Expression.parameter (typeof(int),"x"); Binaryexpression R2=expression.multiply (c, D); Binaryexpression result= Expression.add (R1,R2);//operation of two intermediate nodes, generating endpointsExpression<Func<int,int,int,int,int>> lambda = expression.lambda<func<int,int,int,int,int>>(RESULT,A,B,C,D); Console.WriteLine (Lambda+"");//output ' (i,j,w,x) = ((i*j) + (w*x)) ', z corresponding parameter b,p corresponding parameter aFunc<int,int,int,int,int> f= lambda.compile ();//The lambda expression described by the expression tree is compiled into executable code and the delegate of the lambda expression is generated;Console.WriteLine (F (1,1,1,1) +"");//Output Results 2Console.readkey (); }
The above code consists of a lambda expression tree such as:
Ii. Some common expression tree usages
ConstantExpression: Represents an expression with a constant value
We build a console application
ConstantExpression _constexp = Expression.constant ("AAA",typeof(string));//a constant//Console.WriteLine ("AAA");methodcallexpression _methodcallexp=expression.call (typeof(Console). GetMethod ("WriteLine",Newtype[]{typeof(string)}), _constexp); Expression<Action> Consolelambdaexp = expression.lambda<action>(_METHODCALLEXP); Consolelambdaexp.compile () (); Console.ReadLine ();
Output a constant and look at the results
ParameterExpression : Represents a parameter Expression
ParameterExpression _parameexp = Expression.parameter (typeof(string),"Myparameter"); Methodcallexpression _methodcallexpp= Expression.call (typeof(Console). GetMethod ("WriteLine",NewType[] {typeof(string)}), _parameexp); Expression<Action<string>> _consstringexp = expression.lambda<action<string>>(_methodcallexpp, _parameexp); _consstringexp.compile () ("hello!!");
Output Result:
Methodcallexpression calling a static method
We build a static method that returns a string, passing in a value of type Object
Public Static string Consstr (object str) { string"aa"; Console.WriteLine (_STR); return _str;}
ParameterExpression _paraobj = Expression.parameter (typeof(Object),"Objpara"); Methodcallexpression _mystatemethod= Expression.call (typeof(program). GetMethod ("Consstr",NewType[] {typeof(Object)}), _paraobj); Expression<Func<Object,string>> _meylambdastate = expression.lambda<func<Object,string>>(_mystatemethod, _paraobj);stringS_TR = _meylambdastate.compile () ("ni Hao"); Console.WriteLine ("return Value:"+ s_tr);
Output Result:
Methodcallexpression Invoking instance methods
We write a non-static method
Public string CONSSTR2 (object str) { string"aa"; Console.WriteLine (_STR); return _str;}
Expression.call provides us with the overloads we want:
Program _PG =NewProgram (); ParameterExpression _paraobj2= Expression.parameter (typeof(Object),"Objpara"); Methodcallexpression _mystatemethod2= Expression.call (Expression.constant (_PG),typeof(program). GetMethod ("CONSSTR2"), _paraobj2); Expression<Func<Object,string>> _meylambdastate2 = expression.lambda<func<Object,string>>(_MYSTATEMETHOD2, _paraobj2);stringS_TR2 = _meylambdastate.compile () ("You shi ni"); Console.WriteLine ("return Value:"+ S_TR2);
Output Result:
Unaryexpression: unary operator expression
Use Unaryexpression to make a 5--expression:
ConstantExpression _consnum = expression.constant (5typeof(int= Expression.decrement (_consnum); Expression<Func<int>> _unarylam = expression.lambda<func<int>> (_unaryplus); Console.WriteLine (_unarylam.compile ());
Output Result:
Binaryexpression: Two-tuple operator expression
Binaryexpression We do an example of A+b
ParameterExpression _paraa = Expression.parameter (typeof(int),"a"); ParameterExpression _parab= Expression.parameter (typeof(int),"b"); Binaryexpression _binaadd=Expression.add (_paraa, _parab); Expression<Func<int,int,int>> _mybinaryaddlamb = expression.lambda<func<int,int,int>> (_binaadd,Newparameterexpression[] {_paraa, _parab}); Console.WriteLine ("An expression:"+_mybinaryaddlamb); Console.WriteLine (_mybinaryaddlamb.compile () (3,6));
Output Result:
Two expressions can also be put together: (a+b) * (--C)
ParameterExpression _paraa = Expression.parameter (typeof(int),"a"); ParameterExpression _parab= Expression.parameter (typeof(int),"b"); Binaryexpression _binaadd= Expression.add (_paraa, _parab);//a+bParameterExpression _parac = Expression.parameter (typeof(int),"C"); Unaryexpression _PARADECR= Expression.decrement (_parac);//(a+b) * (--c)Binaryexpression _binamultiply =expression.multiply (_binaadd, _PARADECR); Expression<Func<int,int,int,int>> _mybinarylamb = expression.lambda<func<int,int,int,int>> (_binamultiply,Newparameterexpression[] {_paraa, _parab, _parac}); Console.WriteLine ("An expression:"+_mybinarylamb); Console.WriteLine (_mybinarylamb.compile () (3,6,5));
Output Result:
Iii. Accessing properties using an expression tree
Expression trees can replace reflection, but not necessarily performance, to actually test it, also note that the compile call process involves dynamic code generation, so for performance reasons it's best to cache the resulting expression tree
The next step is to use expression tree to perform property assignments and values, which are implemented in the following two static methods: Creategetpropertyvaluefunc and Createsetpropertyvalueaction. Here is the definition of Creategetpropertyvaluefunc, which returns a func<object.object> delegate:
Public Staticfunc<Object,Object>Creategetpropertyvaluefunc () {
varproperty =typeof(IFoo). GetProperty ("Bar"); vartarget = Expression.parameter (typeof(Object)); varCasttarget = Expression.convert (target,typeof(IFoo)); varGetPropertyValue =Expression.property (Casttarget, property); varCastpropertyvalue = Expression.convert (GetPropertyValue,typeof(Object)); returnexpression.lambda<func<Object,Object>>(Castpropertyvalue, target). Compile (); }
Here is the Createsetpropertyvalueaction method, which returns a action<object.object> delegate:
Public Staticaction<Object,Object>createsetpropertyvalueaction () {varproperty =typeof(IFoo). GetProperty ("Bar"); vartarget = Expression.parameter (typeof(Object)); varPropertyValue = Expression.parameter (typeof(Object)); varCasttarget = Expression.convert (target,typeof(IFoo)); varCastpropertyvalue =Expression.convert (PropertyValue, property. PropertyType); varsetPropertyValue =Expression.call (Casttarget, property. GetSetMethod (), castpropertyvalue); returnexpression.lambda<action<Object,Object>>(setPropertyValue, Target, PropertyValue). Compile (); }
Note: The expression tree water is very deep, here is only the introduction, still need to continue to study use ~
Expression tree of C # secret weapon