在 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), "a"); ParameterExpression b = 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, b); // 打印 a + b 的值 MethodCallExpression method = Expression.Call(null, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(int) }), 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), "a"); ParameterExpression b = Expression.Parameter(typeof(int), "b"); // ab = a + b BinaryExpression ab = Expression.Add(a, b); Expression<Func<int, int, int>> lambda = Expression.Lambda<Func<int, int, int>>(ab, a, 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), "a"); ParameterExpression b = Expression.Parameter(typeof(int), "b"); // ab = a - b BinaryExpression ab = Expression.Subtract(a, b); Expression<Func<int, int, int>> lambda = Expression.Lambda<Func<int, int, int>>(ab, 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), "a"); ParameterExpression b = Expression.Parameter(typeof(int), "b"); // ab = a % b BinaryExpression ab = Expression.Modulo(a, b); Expression<Func<int, int, int>> lambda = Expression.Lambda<Func<int, int, int>>(ab, a, b); int result = lambda.Compile()(200, 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), "a"); ParameterExpression b = 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, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(int) }), a); MethodCallExpression callB = Expression.Call(null, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(int) }), b); BlockExpression block = Expression.Block( new ParameterExpression[] { a, b }, setA, setB, aa, bb, 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, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(int) }), a); MethodCallExpression callB = Expression.Call(null, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(int) }), b); BlockExpression block = Expression.Block( aa, bb, callA, callB ); Expression<Action<int, int>> lambda = Expression.Lambda<Action<int, int>>(block, a, 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 a = Expression.Parameter(typeof(int), "a"); ParameterExpression b = Expression.Parameter(typeof(int), "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, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(int) }), a); MethodCallExpression callB = Expression.Call(null, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(int) }), b); BlockExpression block = Expression.Block( new ParameterExpression[] { a, b }, SetA, SetB, aa, bb, callA, 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,b; ParameterExpression a = Expression.Parameter(typeof(int), "a"); ParameterExpression b = Expression.Parameter(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, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(int) }), a); MethodCallExpression callB = Expression.Call(null, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(int) }), b); BlockExpression block = Expression.Block( new ParameterExpression[] { a, b }, aa, bb, callA, callB ); Expression<Action<int, int>> lambda = Expression.Lambda<Action<int, int>>(block, a, b); lambda.Compile()(10, 10); Console.ReadKey();
.Lambda #Lambda1<System.Action`2[System.Int32,System.Int32]>( System.Int32 $a, 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; ParameterExpression a = Expression.Parameter(typeof(int), "a"); ParameterExpression b = Expression.Parameter(typeof(int), "b"); // a = 21,b = 10; BinaryExpression setA = Expression.Assign(a, 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, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(bool) }), Expression.Equal(a, b)); // Console.Write("a < b :"); // Console.WriteLine(a < b); MethodCallExpression call2 = Expression.Call(null, typeof(Console).GetMethod("Write", new Type[] { typeof(string) }), Expression.Constant("a < b :")); MethodCallExpression call22 = Expression.Call(null, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(bool) }), Expression.LessThan(a, b)); // Console.Write("a > b :"); // Console.WriteLine(a > b); MethodCallExpression call3 = Expression.Call(null, typeof(Console).GetMethod("Write", new Type[] { typeof(string) }), Expression.Constant("a > b :")); MethodCallExpression call33 = Expression.Call(null, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(bool) }), 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, typeof(Console).GetMethod("Write", new Type[] { typeof(string) }), Expression.Constant("a <= b:")); MethodCallExpression call44 = Expression.Call(null, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(bool) }), Expression.LessThanOrEqual(a, b)); // Console.Write("a >= b:"); // Console.WriteLine(b >= a); MethodCallExpression call5 = Expression.Call(null, typeof(Console).GetMethod("Write", new Type[] { typeof(string) }), Expression.Constant("a >= b:")); MethodCallExpression call55 = Expression.Call(null, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(bool) }), Expression.GreaterThanOrEqual(a, b)); BlockExpression block = Expression.Block(new ParameterExpression[] { a, b }, setA, setB, 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), "a"); ParameterExpression b = Expression.Parameter(typeof(int), "b"); BinaryExpression setA = Expression.Assign(a, Expression.Constant(10)); BinaryExpression setB = Expression.Assign(b, Expression.Constant(11)); //Console.Write("[a == b && a > b]:"); //Console.WriteLine(a == b && a > b); MethodCallExpression call1 = Expression.Call(null, typeof(Console).GetMethod("Write", new Type[] { typeof(string) }), Expression.Constant("[a == b && a > b]:")); MethodCallExpression call2 = Expression.Call( null, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(bool) }), Expression.AndAlso(Expression.Equal(a, b), Expression.GreaterThan(a, b)) ); //Console.Write("[a > b || a == b]:"); //Console.WriteLine(a > b || a == b); MethodCallExpression call3 = Expression.Call(null, typeof(Console).GetMethod("Write", new Type[] { typeof(string) }), Expression.Constant("[a > b || a == b]:")); MethodCallExpression call4 = Expression.Call( null, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(bool) }), Expression.OrElse(Expression.Equal(a, b), Expression.GreaterThan(a, b)) ); //Console.Write("[!(a == b)]:"); //Console.WriteLine(!(a == b)); MethodCallExpression call5 = Expression.Call(null, typeof(Console).GetMethod("Write", new Type[] { typeof(string) }), Expression.Constant("[!(a == b)]:")); MethodCallExpression call6 = Expression.Call( null, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(bool) }), Expression.Not(Expression.Equal(a, b)) ); BlockExpression block = Expression.Block( new ParameterExpression[] { a, b }, setA, setB, call1, call2, call3, call4, call5, 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;到此这篇关于C#五类运算符使用表达式树进行操作的文章就介绍到这了。希望对大家的学习有所帮助,也希望大家多多支持。
查看更多关于C#五类运算符使用表达式树进行操作的详细内容...