4. 五类运算符的表达
[TOC]
在 C# 中,算术运算符,有以下类型
  • 算术运算符
  • 关系运算符
  • 逻辑运算符
  • 位运算符
  • 赋值运算符
  • 其他运算符
这些运算符根据参数的多少,可以分作一元运算符、二元运算符、三元运算符。本文将围绕这些运算符,演示如何使用表达式树进行操作。
对于一元运算符和二元运算符的 Expression 的子类型如下:
1
UnaryExpression; //一元运算表达式
2
BinaryExpression; //二元运算表达式
Copied!

一,算术运算符

运算符
描述
+
把两个操作数相加
-
从第一个操作数中减去第二个操作数
*
把两个操作数相乘
/
分子除以分母
%
取模运算符,整除后的余数
++
自增运算符,整数值增加 1
--
自减运算符,整数值减少 1

+ 与 Add()

正常代码
1
int a;
2
int b;
3
a = 100;
4
b = 200;
5
var ab = a + b;
6
Console.WriteLine(ab);
Copied!
使用表达式树构建
1
ParameterExpression a = Expression.Parameter(typeof(int), "a");
2
ParameterExpression b = Expression.Parameter(typeof(int), "b");
3
4
// ab = a + b
5
BinaryExpression ab = Expression.Add(a, b);
6
7
// 打印 a + b 的值
8
MethodCallExpression method = Expression.Call(null, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(int) }), ab);
9
10
Expression<Action<int, int>> lambda = Expression.Lambda<Action<int, int>>(method, a, b);
11
lambda.Compile()(100, 200);
12
13
Console.ReadKey();
Copied!
如果想复杂一些,使用 来执行:
1
ParameterExpression a = Expression.Parameter(typeof(int), "a");
2
ParameterExpression b = Expression.Parameter(typeof(int), "b");
3
4
// 别忘记了赋值
5
BinaryExpression aa = Expression.Assign(a, Expression.Constant(100, typeof(int)));
6
BinaryExpression bb = Expression.Assign(b, Expression.Constant(200, typeof(int)));
7
8
// ab = a + b
9
BinaryExpression ab = Expression.Add(a, b);
10
11
// 打印 a + b 的值
12
MethodCallExpression method = Expression.Call(null, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(int) }), ab);
13
14
// 以块的形式执行代码,相当于{ }
15
// 不需要纠结这里,后面会有详细说明,重点是上面
16
var call = Expression.Block(new ParameterExpression[] { a, b }, aa, bb, method);
17
Expression<Action> lambda = Expression.Lambda<Action>(call);
18
lambda.Compile()();
Copied!
上面两个示例,是使用表达式树计算结果,然后还是使用表达式树打印结果。
前者依赖外界传入参数值,赋予 a、b,后者则全部使用表达式树赋值和运算。
那么,如何通过表达式树执行运算,获取执行结果呢?
1
ParameterExpression a = Expression.Parameter(typeof(int), "a");
2
ParameterExpression b = Expression.Parameter(typeof(int), "b");
3
4
// ab = a + b
5
BinaryExpression ab = Expression.Add(a, b);
6
7
Expression<Func<int, int, int>> lambda = Expression.Lambda<Func<int, int, int>>(ab, a, b);
8
int result = lambda.Compile()(100, 200);
9
10
Console.WriteLine(result);
11
Console.ReadKey();
Copied!
这些区别在于如何编写 Expression.Lambda()
另外,使用 AddChecked() 可以检查操作溢出。

- 与 Subtract()

与加法一致,此处不再赘述,SubtractChecked() 可以检查溢出。
a - b ,结果是 100 。
1
ParameterExpression a = Expression.Parameter(typeof(int), "a");
2
ParameterExpression b = Expression.Parameter(typeof(int), "b");
3
4
// ab = a - b
5
BinaryExpression ab = Expression.Subtract(a, b);
6
7
Expression<Func<int, int, int>> lambda = Expression.Lambda<Func<int, int, int>>(ab, a, b);
8
int result = lambda.Compile()(200, 100);
9
10
Console.WriteLine(result);
Copied!

乘除、取模

乘法
1
// ab = a * b
2
BinaryExpression ab = Expression.Multiply(a, b);
3
// ab = 20000
Copied!
除法
1
// ab = a / b
2
BinaryExpression ab = Expression.Divide(a, b);
3
// ab = 2
Copied!
取模(%)
1
ParameterExpression a = Expression.Parameter(typeof(int), "a");
2
ParameterExpression b = Expression.Parameter(typeof(int), "b");
3
4
// ab = a % b
5
BinaryExpression ab = Expression.Modulo(a, b);
6
7
Expression<Func<int, int, int>> lambda = Expression.Lambda<Func<int, int, int>>(ab, a, b);
8
int result = lambda.Compile()(200, 150);
9
// ab = 50
10
Console.WriteLine(result);
11
Console.ReadKey();
Copied!

自增自减

自增自减有两种模型,一种是 x++ 或 x--,另一种是 ++x 或 --x
他们都是属于 UnaryExpression 类型。
算术运算符
表达式树
说明
x++
Expression.PostIncrementAssign()
后置
x--
Expression.PostDecrementAssign()
后置
++x
Expression.PreIncrementAssign()
前置
--x
Expression.PreDecrementAssign()
前置
巧记:Post 后置, Pre 前置;Increment 是加,Decrement是减;Assign与赋值有关(后面会说到);
x++x-- 的使用
1
int a = 10;
2
int b = 10;
3
a++;
4
b--;
5
Console.WriteLine(a);
6
Console.WriteLine(b);
Copied!
1
// int a,b;
2
ParameterExpression a = Expression.Parameter(typeof(int), "a");
3
ParameterExpression b = Expression.Parameter(typeof(int), "b");
4
5
// a = 10,b = 10;
6
BinaryExpression setA = Expression.Assign(a, Expression.Constant(10));
7
BinaryExpression setB = Expression.Assign(b, Expression.Constant(10));
8
9
// a++
10
UnaryExpression aa = Expression.PostIncrementAssign(a);
11
12
// b--
13
UnaryExpression bb = Expression.PostDecrementAssign(b);
14
15
//Console.WriteLine(a);
16
//Console.WriteLine(b);
17
MethodCallExpression callA = Expression.Call(null, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(int) }), a);
18
MethodCallExpression callB = Expression.Call(null, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(int) }), b);
19
20
BlockExpression block = Expression.Block(
21
new ParameterExpression[] { a, b },
22
setA,
23
setB,
24
aa,
25
bb,
26
callA,
27
callB
28
);
29
30
Expression<Action> lambda = Expression.Lambda<Action>(block);
31
lambda.Compile()();
32
33
Console.ReadKey();
Copied!
如果想把参数从外面传入,设置 a,b
1
// int a,b;
2
ParameterExpression a = Expression.Variable(typeof(int), "a");
3
ParameterExpression b = Expression.Variable(typeof(int), "b");
4
5
// a++
6
UnaryExpression aa = Expression.PostIncrementAssign(a);
7
8
// b--
9
UnaryExpression bb = Expression.PostDecrementAssign(b);
10
11
//Console.WriteLine(a);
12
//Console.WriteLine(b);
13
MethodCallExpression callA = Expression.Call(null, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(int) }), a);
14
MethodCallExpression callB = Expression.Call(null, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(int) }), b);
15
16
BlockExpression block = Expression.Block(
17
aa,
18
bb,
19
callA,
20
callB
21
);
22
23
Expression<Action<int, int>> lambda = Expression.Lambda<Action<int, int>>(block, a, b);
24
lambda.Compile()(10, 10);
25
Console.ReadKey();
Copied!
生成的表达式树如下
1
.Lambda #Lambda1<System.Action`2[System.Int32,System.Int32]>(
2
System.Int32 $a,
3
System.Int32 $b) {
4
.Block() {
5
$a++;
6
$b--;
7
.Call System.Console.WriteLine($a);
8
.Call System.Console.WriteLine($b)
9
}
10
}
Copied!
为了理解一下 Expression.Block(),可以在这里学习一下(后面会说到 Block())。
1
// int a,b;
2
ParameterExpression a = Expression.Parameter(typeof(int), "a");
3
ParameterExpression b = Expression.Parameter(typeof(int), "b");
4
ParameterExpression c = Expression.Variable(typeof(int), "c");
5
6
BinaryExpression SetA = Expression.Assign(a, c);
7
BinaryExpression SetB = Expression.Assign(b, c);
8
// a++
9
UnaryExpression aa = Expression.PostIncrementAssign(a);
10
11
// b--
12
UnaryExpression bb = Expression.PostDecrementAssign(b);
13
14
//Console.WriteLine(a);
15
//Console.WriteLine(b);
16
MethodCallExpression callA = Expression.Call(null, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(int) }), a);
17
MethodCallExpression callB = Expression.Call(null, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(int) }), b);
18
19
BlockExpression block = Expression.Block(
20
new ParameterExpression[] { a, b },
21
SetA,
22
SetB,
23
aa,
24
bb,
25
callA,
26
callB
27
);
28
29
Expression<Action<int>> lambda = Expression.Lambda<Action<int>>(block, c);
30
lambda.Compile()(10);
31
32
Console.ReadKey();
Copied!
为什么这里要多加一个 c 呢?我们来看看生成的表达式树
1
.Lambda #Lambda1<System.Action`1[System.Int32]>(System.Int32 $c) {
2
.Block(
3
System.Int32 $a,
4
System.Int32 $b) {
5
$a = $c;
6
$b = $c;
7
$a++;
8
$b--;
9
.Call System.Console.WriteLine($a);
10
.Call System.Console.WriteLine($b)
11
}
12
}
Copied!
观察一下下面代码生成的表达式树
1
// int a,b;
2
ParameterExpression a = Expression.Parameter(typeof(int), "a");
3
ParameterExpression b = Expression.Parameter(typeof(int), "b");
4
5
// a++
6
UnaryExpression aa = Expression.PostIncrementAssign(a);
7
8
// b--
9
UnaryExpression bb = Expression.PostDecrementAssign(b);
10
11
//Console.WriteLine(a);
12
//Console.WriteLine(b);
13
MethodCallExpression callA = Expression.Call(null, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(int) }), a);
14
MethodCallExpression callB = Expression.Call(null, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(int) }), b);
15
16
BlockExpression block = Expression.Block(
17
new ParameterExpression[] { a, b },
18
aa,
19
bb,
20
callA,
21
callB
22
);
23
24
Expression<Action<int, int>> lambda = Expression.Lambda<Action<int, int>>(block, a, b);
25
lambda.Compile()(10, 10);
26
Console.ReadKey();
Copied!
1
.Lambda #Lambda1<System.Action`2[System.Int32,System.Int32]>(
2
System.Int32 $a,
3
System.Int32 $b) {
4
.Block(
5
System.Int32 $a,
6
System.Int32 $b) {
7
$a++;
8
$b--;
9
.Call System.Console.WriteLine($a);
10
.Call System.Console.WriteLine($b)
11
}
12
}
Copied!
关于前置的自增自减,按照上面示例编写即可,但是需要注意的是, ++x 和 --x ,是“先运算后增/自减”。

二,关系运算符

==、!=、>、<、>=、<=

C# 中的关系运算符如下
运算符
描述
==
检查两个操作数的值是否相等,如果相等则条件为真。
!=
检查两个操作数的值是否相等,如果不相等则条件为真。
>
检查左操作数的值是否大于右操作数的值,如果是则条件为真。
<
检查左操作数的值是否小于右操作数的值,如果是则条件为真。
>=
检查左操作数的值是否大于或等于右操作数的值,如果是则条件为真。
<=
检查左操作数的值是否小于或等于右操作数的值,如果是则条件为真。
== 表示相等比较,如果是值类型和 string 类型,则比较值是否相同;如果是引用类型,则比较引用的地址是否相等。
其它的关系运算符则是仅比较值类型的大小。
实例代码
1
int a = 21;
2
int b = 10;
3
Console.Write("a == b:");
4
Console.WriteLine(a == b);
5
6
Console.Write("a < b :");
7
Console.WriteLine(a < b);
8
9
10
Console.Write("a > b :");
11
Console.WriteLine(a > b);
12
13
// 改变 a 和 b 的值
14
a = 5;
15
b = 20;
16
17
Console.Write("a <= b:");
18
Console.WriteLine(a <= b);
19
20
21
Console.Write("a >= b:");
22
Console.WriteLine(b >= a);
23
24
Console.ReadKey();
Copied!
使用表达式树实现
1
// int a,b;
2
ParameterExpression a = Expression.Parameter(typeof(int), "a");
3
ParameterExpression b = Expression.Parameter(typeof(int), "b");
4
5
// a = 21,b = 10;
6
BinaryExpression setA = Expression.Assign(a, Expression.Constant(21));
7
BinaryExpression setB = Expression.Assign(b, Expression.Constant(20));
8
9
// Console.Write("a == b:");
10
// Console.WriteLine(a == b);
11
MethodCallExpression call1 = Expression.Call(null,
12
typeof(Console).GetMethod("Write", new Type[] { typeof(string) }),
13
Expression.Constant("a == b:"));
14
MethodCallExpression call11 = Expression.Call(null,
15
typeof(Console).GetMethod("WriteLine", new Type[] { typeof(bool) }),
16
Expression.Equal(a, b));
17
18
// Console.Write("a < b :");
19
// Console.WriteLine(a < b);
20
MethodCallExpression call2 = Expression.Call(null,
21
typeof(Console).GetMethod("Write", new Type[] { typeof(string) }),
22
Expression.Constant("a < b :"));
23
MethodCallExpression call22 = Expression.Call(null,
24
typeof(Console).GetMethod("WriteLine", new Type[] { typeof(bool) }),
25
Expression.LessThan(a, b));
26
27
// Console.Write("a > b :");
28
// Console.WriteLine(a > b);
29
MethodCallExpression call3 = Expression.Call(null,
30
typeof(Console).GetMethod("Write", new Type[] { typeof(string) }),
31
Expression.Constant("a > b :"));
32
MethodCallExpression call33 = Expression.Call(null,
33
typeof(Console).GetMethod("WriteLine", new Type[] { typeof(bool) }),
34
Expression.GreaterThan(a, b));
35
36
37
// 改变 a 和 b 的值
38
// a = 5;
39
// b = 20;
40
BinaryExpression setAa = Expression.Assign(a, Expression.Constant(5));
41
BinaryExpression setBb = Expression.Assign(b, Expression.Constant(20));
42
43
// Console.Write("a <= b:");
44
// Console.WriteLine(a <= b);
45
MethodCallExpression call4 = Expression.Call(null,
46
typeof(Console).GetMethod("Write", new Type[] { typeof(string) }),
47
Expression.Constant("a <= b:"));
48
MethodCallExpression call44 = Expression.Call(null,
49
typeof(Console).GetMethod("WriteLine", new Type[] { typeof(bool) }),
50
Expression.LessThanOrEqual(a, b));
51
52
// Console.Write("a >= b:");
53
// Console.WriteLine(b >= a);
54
MethodCallExpression call5 = Expression.Call(null,
55
typeof(Console).GetMethod("Write", new Type[] { typeof(string) }),
56
Expression.Constant("a >= b:"));
57
MethodCallExpression call55 = Expression.Call(null,
58
typeof(Console).GetMethod("WriteLine", new Type[] { typeof(bool) }),
59
Expression.GreaterThanOrEqual(a, b));
60
61
BlockExpression block = Expression.Block(new ParameterExpression[] { a, b },
62
setA,
63
setB,
64
call1,
65
call11,
66
call2,
67
call22,
68
call3,
69
call33,
70
setAa,
71
setBb,
72
call4,
73
call44,
74
call5,
75
call55
76
);
77
78
Expression<Action> lambda = Expression.Lambda<Action>(block);
79
lambda.Compile()();
80
Console.ReadKey();
Copied!
生成的表达式树如下
1
.Lambda #Lambda1<System.Action>() {
2
.Block(
3
System.Int32 $a,
4
System.Int32 $b) {
5
$a = 21;
6
$b = 20;
7
.Call System.Console.Write("a == b:");
8
.Call System.Console.WriteLine($a == $b);
9
.Call System.Console.Write("a < b :");
10
.Call System.Console.WriteLine($a < $b);
11
.Call System.Console.Write("a > b :");
12
.Call System.Console.WriteLine($a > $b);
13
$a = 5;
14
$b = 20;
15
.Call System.Console.Write("a <= b:");
16
.Call System.Console.WriteLine($a <= $b);
17
.Call System.Console.Write("a >= b:");
18
.Call System.Console.WriteLine($a >= $b)
19
}
20
}
Copied!

三,逻辑运算符

&&、||、!

运算符
描述
&&
称为逻辑与运算符。如果两个操作数都非零,则条件为真。
||
称为逻辑或运算符。如果两个操作数中有任意一个非零,则条件为真。
!
称为逻辑非运算符。用来逆转操作数的逻辑状态。如果条件为真则逻辑非运算符将使其为假。
逻辑运算符的运行,结果是 true 或 false。
逻辑运算符
表达式树
&&
Expression.AndAlso()
||
Expression.OrElse()
Expression.Not()
1
int a = 10;
2
int b = 11;
3
4
Console.Write("[a == b && a > b]:");
5
Console.WriteLine(a == b && a > b);
6
7
Console.Write("[a > b || a == b]:");
8
Console.WriteLine(a > b || a == b);
9
10
Console.Write("[!(a == b)]:");
11
Console.WriteLine(!(a == b));
12
Console.ReadKey();
Copied!
使用表达式树编写
1
//int a = 10;
2
//int b = 11;
3
ParameterExpression a = Expression.Parameter(typeof(int), "a");
4
ParameterExpression b = Expression.Parameter(typeof(int), "b");
5
BinaryExpression setA = Expression.Assign(a, Expression.Constant(10));
6
BinaryExpression setB = Expression.Assign(b, Expression.Constant(11));
7
8
//Console.Write("[a == b && a > b]:");
9
//Console.WriteLine(a == b && a > b);
10
MethodCallExpression call1 = Expression.Call(null, typeof(Console).GetMethod("Write", new Type[] { typeof(string) }), Expression.Constant("[a == b && a > b]:"));
11
12
MethodCallExpression call2 = Expression.Call(
13
null,
14
typeof(Console).GetMethod("WriteLine", new Type[] { typeof(bool) }),
15
Expression.AndAlso(Expression.Equal(a, b), Expression.GreaterThan(a, b))
16
);
17
18
//Console.Write("[a > b || a == b]:");
19
//Console.WriteLine(a > b || a == b);
20
MethodCallExpression call3 = Expression.Call(null, typeof(Console).GetMethod("Write", new Type[] { typeof(string) }), Expression.Constant("[a > b || a == b]:"));
21
MethodCallExpression call4 = Expression.Call(
22
null,
23
typeof(Console).GetMethod("WriteLine", new Type[] { typeof(bool) }),
24
Expression.OrElse(Expression.Equal(a, b), Expression.GreaterThan(a, b))
25
);
26
27
//Console.Write("[!(a == b)]:");
28
//Console.WriteLine(!(a == b));
29
MethodCallExpression call5 = Expression.Call(null, typeof(Console).GetMethod("Write", new Type[] { typeof(string) }), Expression.Constant("[!(a == b)]:"));
30
MethodCallExpression call6 = Expression.Call(
31
null,
32
typeof(Console).GetMethod("WriteLine", new Type[] { typeof(bool) }),
33
Expression.Not(Expression.Equal(a, b))
34
);
35
BlockExpression block = Expression.Block(
36
new ParameterExpression[] { a, b },
37
setA,
38
setB,
39
call1,
40
call2,
41
call3,
42
call4,
43
call5,
44
call6
45
);
46
47
Expression<Action> lambda = Expression.Lambda<Action>(block);
48
lambda.Compile()();
49
Console.ReadKey();
Copied!
生成的表达式树如下
1
.Lambda #Lambda1<System.Action>() {
2
.Block(
3
System.Int32 $a,
4
System.Int32 $b) {
5
$a = 10;
6
$b = 11;
7
.Call System.Console.Write("[a == b && a > b]:");
8
.Call System.Console.WriteLine($a == $b && $a > $b);
9
.Call System.Console.Write("[a > b || a == b]:");
10
.Call System.Console.WriteLine($a == $b || $a > $b);
11
.Call System.Console.Write("[!(a == b)]:");
12
.Call System.Console.WriteLine(!($a == $b))
13
}
14
}
Copied!

四,位运算符

&、|、^、~、<<、>>

运算符
描述
实例
&
如果同时存在于两个操作数中,二进制 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;
表达式树里面我没有找到这些运算符的如何编写,如果你找到了,欢迎告诉我。。。