表达式树练习实践:C# 运算符
-
表达式树练习实践:C# 运算符
-
一,算术运算符
- + 与 Add()
- - 与 Subtract()
- 乘除、取模
- 自增自减
-
二,关系运算符
-
三,逻辑运算符
-
四,位运算符
- 五,赋值运算符
- 六,其他运算符
在 C# 中,算术运算符,有以下类型
- 算术运算符
- 关系运算符
- 逻辑运算符
- 位运算符
- 赋值运算符
- 其他运算符
这些运算符根据参数的多少,可以分作一元运算符、二元运算符、三元运算符。本文将围绕这些运算符,演示如何使用表达式树进行操作。
对于一元运算符和二元运算符的 Expression 的子类型如下:
UnaryExpression; //一元运算表达式
BinaryExpression; //二元运算表达式
一,算术运算符
运算符 |
描述 |
+ |
把两个操作数相加 |
- |
从第一个操作数中减去第二个操作数 |
* |
把两个操作数相乘 |
/ |
分子除以分母 |
% |
取模运算符,整除后的余数 |
++ |
自增运算符,整数值增加 1 |
-- |
自减运算符,整数值减少 1 |
+ 与 Add()
正常代码
int a;
int b;
a = 100;
b = 200;
var ab = a + b;
Console.WriteLine(ab);
使用表达式树构建
ParameterExpression a = Expression.Parameter(typeof(int),"a");
ParameterExpression b = Expression.Parameter(typeof(int),"b");
// ab = a + b
BinaryExpression ab = Expression.Add(a,b);
// 打印 a + b 的值
MethodCallExpression method = Expression.Call(null,typeof(Console).GetMethod("WriteLine",new Type[] { typeof(int) }),ab);
Expression<Action<int,int>> lambda = Expression.Lambda<Action<int,int>>(method,a,b);
lambda.Compile()(100,200);
Console.ReadKey();
如果想复杂一些,使用 块 来执行:
ParameterExpression a = Expression.Parameter(typeof(int),"b");
// 别忘记了赋值
BinaryExpression aa = Expression.Assign(a,Expression.Constant(100,typeof(int)));
BinaryExpression bb = Expression.Assign(b,Expression.Constant(200,typeof(int)));
// ab = a + b
BinaryExpression ab = Expression.Add(a,ab);
// 以块的形式执行代码,相当于{ }
// 不需要纠结这里,后面会有详细说明,重点是上面
var call = Expression.Block(new ParameterExpression[] { a,b },aa,bb,method);
Expression<Action> lambda = Expression.Lambda<Action>(call);
lambda.Compile()();
上面两个示例,是使用表达式树计算结果,然后还是使用表达式树打印结果。
前者依赖外界传入参数值,赋予 a、b,后者则全部使用表达式树赋值和运算。
那么,如何通过表达式树执行运算,获取执行结果呢?
ParameterExpression a = Expression.Parameter(typeof(int),b);
Expression<Func<int,int,int>> lambda = Expression.Lambda<Func<int,int>>(ab,b);
int result = lambda.Compile()(100,200);
Console.WriteLine(result);
Console.ReadKey();
这些区别在于如何编写 Expression.Lambda() 。
另外,使用 AddChecked() 可以检查操作溢出。
- 与 Subtract()
与加法一致,此处不再赘述,SubtractChecked() 可以检查溢出。
a - b ,结果是 100 。
ParameterExpression a = Expression.Parameter(typeof(int),"b");
// ab = a - b
BinaryExpression ab = Expression.Subtract(a,b);
int result = lambda.Compile()(200,100);
Console.WriteLine(result);
乘除、取模
乘法
// ab = a * b
BinaryExpression ab = Expression.Multiply(a,b);
// ab = 20000
除法
// ab = a / b
BinaryExpression ab = Expression.Divide(a,b);
// ab = 2
取模(%)
ParameterExpression a = Expression.Parameter(typeof(int),"b");
// ab = a % b
BinaryExpression ab = Expression.Modulo(a,150);
// ab = 50
Console.WriteLine(result);
Console.ReadKey();
自增自减
自增自减有两种模型,一种是 x++ 或 x-- ,另一种是 ++x 或 --x 。
他们都是属于 UnaryExpression 类型。
算术运算符 |
表达式树 |
说明 |
x++ |
Expression.PostIncrementAssign() |
后置 |
x-- |
Expression.PostDecrementAssign() |
后置 |
++x |
Expression.PreIncrementAssign() |
前置 |
--x |
Expression.PreDecrementAssign() |
前置 |
巧记:Post 后置, Pre 前置;Increment 是加,Decrement是减;Assign与赋值有关(后面会说到);
x++ 与 x-- 的使用
int a = 10;
int b = 10;
a++;
b--;
Console.WriteLine(a);
Console.WriteLine(b);
// int a,b;
ParameterExpression a = Expression.Parameter(typeof(int),"b");
// a = 10,b = 10;
BinaryExpression setA = Expression.Assign(a,Expression.Constant(10));
BinaryExpression setB = Expression.Assign(b,Expression.Constant(10));
// a++
UnaryExpression aa = Expression.PostIncrementAssign(a);
// b--
UnaryExpression bb = Expression.PostDecrementAssign(b);
//Console.WriteLine(a);
//Console.WriteLine(b);
MethodCallExpression callA = Expression.Call(null,a);
MethodCallExpression callB = Expression.Call(null,b);
BlockExpression block = Expression.Block(
new ParameterExpression[] { a,setA,setB,callA,callB
);
Expression<Action> lambda = Expression.Lambda<Action>(block);
lambda.Compile()();
Console.ReadKey();
如果想把参数从外面传入,设置 a,b
// int a,b;
ParameterExpression a = Expression.Variable(typeof(int),"a");
ParameterExpression b = Expression.Variable(typeof(int),"b");
// a++
UnaryExpression aa = Expression.PostIncrementAssign(a);
// b--
UnaryExpression bb = Expression.PostDecrementAssign(b);
//Console.WriteLine(a);
//Console.WriteLine(b);
MethodCallExpression callA = Expression.Call(null,b);
BlockExpression block = Expression.Block(
aa,callB
);
Expression<Action<int,int>>(block,b);
lambda.Compile()(10,10);
Console.ReadKey();
生成的表达式树如下
.Lambda #Lambda1<System.Action`2[System.Int32,System.Int32]>(
System.Int32 $a,System.Int32 $b) {
.Block() {
$a++;
$b--;
.Call System.Console.WriteLine($a);
.Call System.Console.WriteLine($b)
}
}
为了理解一下 Expression.Block() ,可以在这里学习一下(后面会说到 Block() )。
// int a,"b");
ParameterExpression c = Expression.Variable(typeof(int),"c");
BinaryExpression SetA = Expression.Assign(a,c);
BinaryExpression SetB = Expression.Assign(b,c);
// a++
UnaryExpression aa = Expression.PostIncrementAssign(a);
// b--
UnaryExpression bb = Expression.PostDecrementAssign(b);
//Console.WriteLine(a);
//Console.WriteLine(b);
MethodCallExpression callA = Expression.Call(null,SetA,SetB,callB
);
Expression<Action<int>> lambda = Expression.Lambda<Action<int>>(block,c);
lambda.Compile()(10);
Console.ReadKey();
为什么这里要多加一个 c 呢?我们来看看生成的表达式树
.Lambda #Lambda1<System.Action`1[System.Int32]>(System.Int32 $c) {
.Block(
System.Int32 $a,System.Int32 $b) {
$a = $c;
$b = $c;
$a++;
$b--;
.Call System.Console.WriteLine($a);
.Call System.Console.WriteLine($b)
}
}
观察一下下面代码生成的表达式树
// int a,10);
Console.ReadKey();
.Lambda #Lambda1<System.Action`2[System.Int32,System.Int32 $b) {
.Block(
System.Int32 $a,System.Int32 $b) {
$a++;
$b--;
.Call System.Console.WriteLine($a);
.Call System.Console.WriteLine($b)
}
}
关于前置的自增自减,按照上面示例编写即可,但是需要注意的是, ++x 和 --x ,是“先运算后增/自减”。
二,关系运算符
==、!=、>、<、>=、<=
C# 中的关系运算符如下
运算符 |
描述 |
== |
检查两个操作数的值是否相等,如果相等则条件为真。 |
!= |
检查两个操作数的值是否相等,如果不相等则条件为真。 |
> |
检查左操作数的值是否大于右操作数的值,如果是则条件为真。 |
< |
检查左操作数的值是否小于右操作数的值,如果是则条件为真。 |
>= |
检查左操作数的值是否大于或等于右操作数的值,如果是则条件为真。 |
<= |
检查左操作数的值是否小于或等于右操作数的值,如果是则条件为真。 |
== 表示相等比较,如果是值类型和 string 类型,则比较值是否相同;如果是引用类型,则比较引用的地址是否相等。
其它的关系运算符则是仅比较值类型的大小。
实例代码
int a = 21;
int b = 10;
Console.Write("a == b:");
Console.WriteLine(a == b);
Console.Write("a < b :");
Console.WriteLine(a < b);
Console.Write("a > b :");
Console.WriteLine(a > b);
// 改变 a 和 b 的值
a = 5;
b = 20;
Console.Write("a <= b:");
Console.WriteLine(a <= b);
Console.Write("a >= b:");
Console.WriteLine(b >= a);
Console.ReadKey();
使用表达式树实现
// int a,"b");
// a = 21,Expression.Constant(21));
BinaryExpression setB = Expression.Assign(b,Expression.Constant(20));
// Console.Write("a == b:");
// Console.WriteLine(a == b);
MethodCallExpression call1 = Expression.Call(null,typeof(Console).GetMethod("Write",new Type[] { typeof(string) }),Expression.Constant("a == b:"));
MethodCallExpression call11 = Expression.Call(null,new Type[] { typeof(bool) }),Expression.Equal(a,b));
// Console.Write("a < b :");
// Console.WriteLine(a < b);
MethodCallExpression call2 = Expression.Call(null,Expression.Constant("a < b :"));
MethodCallExpression call22 = Expression.Call(null,Expression.LessThan(a,b));
// Console.Write("a > b :");
// Console.WriteLine(a > b);
MethodCallExpression call3 = Expression.Call(null,Expression.Constant("a > b :"));
MethodCallExpression call33 = Expression.Call(null,Expression.GreaterThan(a,b));
// 改变 a 和 b 的值
// a = 5;
// b = 20;
BinaryExpression setAa = Expression.Assign(a,Expression.Constant(5));
BinaryExpression setBb = Expression.Assign(b,Expression.Constant(20));
// Console.Write("a <= b:");
// Console.WriteLine(a <= b);
MethodCallExpression call4 = Expression.Call(null,Expression.Constant("a <= b:"));
MethodCallExpression call44 = Expression.Call(null,Expression.LessThanOrEqual(a,b));
// Console.Write("a >= b:");
// Console.WriteLine(b >= a);
MethodCallExpression call5 = Expression.Call(null,Expression.Constant("a >= b:"));
MethodCallExpression call55 = Expression.Call(null,Expression.GreaterThanOrEqual(a,b));
BlockExpression block = Expression.Block(new ParameterExpression[] { a,call1,call11,call2,call22,call3,call33,setAa,setBb,call4,call44,call5,call55
);
Expression<Action> lambda = Expression.Lambda<Action>(block);
lambda.Compile()();
Console.ReadKey();
生成的表达式树如下
.Lambda #Lambda1<System.Action>() {
.Block(
System.Int32 $a,System.Int32 $b) {
$a = 21;
$b = 20;
.Call System.Console.Write("a == b:");
.Call System.Console.WriteLine($a == $b);
.Call System.Console.Write("a < b :");
.Call System.Console.WriteLine($a < $b);
.Call System.Console.Write("a > b :");
.Call System.Console.WriteLine($a > $b);
$a = 5;
$b = 20;
.Call System.Console.Write("a <= b:");
.Call System.Console.WriteLine($a <= $b);
.Call System.Console.Write("a >= b:");
.Call System.Console.WriteLine($a >= $b)
}
}
三,逻辑运算符
&&、||、!
运算符 |
描述 |
&& |
称为逻辑与运算符。如果两个操作数都非零,则条件为真。 |
|| |
称为逻辑或运算符。如果两个操作数中有任意一个非零,则条件为真。 |
! |
称为逻辑非运算符。用来逆转操作数的逻辑状态。如果条件为真则逻辑非运算符将使其为假。 |
逻辑运算符的运行,结果是 true 或 false。
逻辑运算符 |
表达式树 |
&& |
Expression.AndAlso() |
|| |
Expression.OrElse() |
! |
Expression.Not() |
int a = 10;
int b = 11;
Console.Write("[a == b && a > b]:");
Console.WriteLine(a == b && a > b);
Console.Write("[a > b || a == b]:");
Console.WriteLine(a > b || a == b);
Console.Write("[!(a == b)]:");
Console.WriteLine(!(a == b));
Console.ReadKey();
使用表达式树编写
//int a = 10;
//int b = 11;
ParameterExpression a = Expression.Parameter(typeof(int),"b");
BinaryExpression setA = Expression.Assign(a,Expression.Constant(11));
//Console.Write("[a == b && a > b]:");
//Console.WriteLine(a == b && a > b);
MethodCallExpression call1 = Expression.Call(null,Expression.Constant("[a == b && a > b]:"));
MethodCallExpression call2 = Expression.Call(
null,Expression.AndAlso(Expression.Equal(a,b),b))
);
//Console.Write("[a > b || a == b]:");
//Console.WriteLine(a > b || a == b);
MethodCallExpression call3 = Expression.Call(null,Expression.Constant("[a > b || a == b]:"));
MethodCallExpression call4 = Expression.Call(
null,Expression.OrElse(Expression.Equal(a,b))
);
//Console.Write("[!(a == b)]:");
//Console.WriteLine(!(a == b));
MethodCallExpression call5 = Expression.Call(null,Expression.Constant("[!(a == b)]:"));
MethodCallExpression call6 = Expression.Call(
null,Expression.Not(Expression.Equal(a,b))
);
BlockExpression block = Expression.Block(
new ParameterExpression[] { a,call6
);
Expression<Action> lambda = Expression.Lambda<Action>(block);
lambda.Compile()();
Console.ReadKey();
生成的表达式树如下
.Lambda #Lambda1<System.Action>() {
.Block(
System.Int32 $a,System.Int32 $b) {
$a = 10;
$b = 11;
.Call System.Console.Write("[a == b && a > b]:");
.Call System.Console.WriteLine($a == $b && $a > $b);
.Call System.Console.Write("[a > b || a == b]:");
.Call System.Console.WriteLine($a == $b || $a > $b);
.Call System.Console.Write("[!(a == b)]:");
.Call System.Console.WriteLine(!($a == $b))
}
}
四,位运算符
&、|、^、~、<<、>>
运算符 |
描述 |
实例 |
& |
如果同时存在于两个操作数中,二进制 AND 运算符复制一位到结果中。 |
(A & B) 将得到 12,即为 0000 1100 |
| |
如果存在于任一操作数中,二进制 OR 运算符复制一位到结果中。 |
(A | B) 将得到 61,即为 0011 1101 |
^ |
如果存在于其中一个操作数中但不同时存在于两个操作数中,二进制异或运算符复制一位到结果中。 |
(A ^ B) 将得到 49,即为 0011 0001 |
~ |
按位取反运算符是一元运算符,具有"翻转"位效果,即0变成1,1变成0,包括符号位。 |
(~A ) 将得到 -61,即为 1100 0011,一个有符号二进制数的补码形式。 |
<< |
二进制左移运算符。左操作数的值向左移动右操作数指定的位数。 |
A << 2 将得到 240,即为 1111 0000 |
>> |
二进制右移运算符。左操作数的值向右移动右操作数指定的位数。 |
A >> 2 将得到 15,即为 0000 1111 |
限于篇幅,就写示例了。
位运算符 |
表达式树 |
& |
Expression.Add(Expression left,Expression right) |
| |
Expression.Or(Expression left,Expression right) |
^ |
Expression.ExclusiveOr(Expression expression) |
~ |
Expression.OnesComplement( Expression expression) |
<< |
Expression.LeftShift(Expression left,Expression right) |
>> |
Expression.RightShift(Expression left,Expression right) |
五,赋值运算符
运算符 |
描述 |
实例 |
= |
简单的赋值运算符,把右边操作数的值赋给左边操作数 |
C = A + B 将把 A + B 的值赋给 C |
+= |
加且赋值运算符,把右边操作数加上左边操作数的结果赋值给左边操作数 |
C += A 相当于 C = C + A |
-= |
减且赋值运算符,把左边操作数减去右边操作数的结果赋值给左边操作数 |
C -= A 相当于 C = C - A |
*= |
乘且赋值运算符,把右边操作数乘以左边操作数的结果赋值给左边操作数 |
C *= A 相当于 C = C * A |
/= |
除且赋值运算符,把左边操作数除以右边操作数的结果赋值给左边操作数 |
C /= A 相当于 C = C / A |
%= |
求模且赋值运算符,求两个操作数的模赋值给左边操作数 |
C %= A 相当于 C = C % A |
<<= |
左移且赋值运算符 |
C <<= 2 等同于 C = C << 2 |
>>= |
右移且赋值运算符 |
C >>= 2 等同于 C = C >> 2 |
&= |
按位与且赋值运算符 |
C &= 2 等同于 C = C & 2 |
^= |
按位异或且赋值运算符 |
C ^= 2 等同于 C = C ^ 2 |
|= |
按位或且赋值运算符 |
C |= 2 等同于 C = C | 2 |
限于篇幅,请自行领略... ...
运算符 |
表达式树 |
= |
Expression.Assign |
+= |
Expression.AddAssign |
-= |
Expression.SubtractAssign |
*= |
Expression.MultiplyAssign |
/= |
Expression.DivideAssign |
%= |
Expression.ModuloAssign |
<<= |
Expression.LeftShiftAssign |
>>= |
Expression.RightShiftAssign |
&= |
Expression.AndAssign |
^= |
Expression.ExclusiveOrAssign |
|= |
Expression.OrAssign |
^= ,注意有两种意思一种是位运算符的异或(ExclusiveOrAssign) ,一种是算术运算符的幂运算(PowerAssign) 。
六,其他运算符
运算符 |
描述 |
实例 |
sizeof() |
返回数据类型的大小。 |
sizeof(int),将返回 4. |
typeof() |
返回 class 的类型。 |
typeof(StreamReader); |
& |
返回变量的地址。 |
&a; 将得到变量的实际地址。 |
* |
变量的指针。 |
*a; 将指向一个变量。 |
? : |
条件表达式 |
如果条件为真 ? 则为 X : 否则为 Y |
is |
判断对象是否为某一类型。 |
If( Ford is Car) // 检查 Ford 是否是 Car 类的一个对象。 |
as |
强制转换,即使转换失败也不会抛出异常。 |
Object obj = new StringReader("Hello"); StringReader r = obj as StringReader; |
表达式树里面我没有找到这些运算符的如何编写,如果你找到了,欢迎告诉我。。。 (编辑:李大同)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|