Продолжим наше
увлекательное погружение в мир деревьев выражений языка C#. Мне очень понравилось
работать с предыдущей статьей, так как я сам узнал много нового о деревьях
выражений и их использовании. Поэтому надеюсь, что сегодняшний материал будет для вас не менее занятным. Предыдущая статья закончилась рассмотрением функции Equal,
пожалуй, продолжу в том же духе рассматривать в алфавитном порядке далее.
ExclusiveOr
Метод Expression.ExclusiveOr
создает
BinaryExpression,
который представляет собой побитовую операцию XOR (побитовая операция
исключающего OR).
Так будет выглядеть
таблица соответствия:
Пример, как это будет
выглядеть, если расписать в виде таблицы:
Пример:
Expression exclusiveOrExpr = Expression.ExclusiveOr(
Expression.Constant(5),
Expression.Constant(3)
);
Console.WriteLine(Expression.Lambda<Func<int>>(exclusiveOrExpr).Compile()());
Результат:
6
ExclusiveOrAssign
Этот метод аналогичен
предыдущему рассмотренному методу, за исключением того, что в данном методе мы
присваиваем полученный результат в переменную. Поэтому не отвлекаясь на
детальное расписывание, просто посмотрим пример, так как мы уже рассматривали
варианты использования методов для построения деревьев выражений с приставкой Assign в конце
метода.
Пример:
ParameterExpression parameterExpr = Expression.Parameter(typeof (int), "n");
Expression assignExpr = Expression.Assign(parameterExpr, Expression.Constant(5));
Expression bodyExpression = Expression.Block(
new ParameterExpression[] { parameterExpr },
assignExpr,
Expression.ExclusiveOrAssign(parameterExpr, Expression.Constant(3))
);
Console.WriteLine(Expression.Lambda<Func<int>>(bodyExpression).Compile()());
Результат:
6
Field
На этой функции
хотелось бы заострить ваше внимание. Эта функция создает MemberExpression,
которое позволяет получить доступ к полу по конкретному имени. Если вы помните, то чтобы, например, получить доступ к private
полу
в каком-то классе, нам нужно было писать очень некрасивый и не совсем
интуитивно понятный код. Давайте рассмотрим пример, в котором вычитаем с
тестового класса private
поле.
public class A
{
public A(string name)
{
_p = name;
}
private string _p;
public string P
{
get { return _p; }
}
}
Функция для получения
поля _p
приведена
ниже.
static void Main(string[] args)
{
A a = new A("Hello");
string p = (string)(typeof(A).GetField("_p", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(a));
Console.WriteLine(p);
Console.ReadLine();
}
Так как GetValue возвращает
object,
я
сразу привел его к нужному типу. На экран после запуска будет выведен текст "Hello".
Давайте теперь
рассмотрим пример, как это можно сделать с помощью деревьев выражений с
использованием функции Field.
static void Main(string[] args)
{
A a = new A("Hello");
ParameterExpression paramExpr = Expression.Parameter(typeof(A), "arg");
MemberExpression member = Expression.Field(paramExpr, "_p");
string result = Expression.Lambda<Func<A, string>>(member, paramExpr).Compile()(a);
Console.WriteLine(result);
Console.ReadLine();
}
Код выглядит симпатичнее, хотя немного больше по размеру. Но мы можем переписать наш пример по такому принципу.
Выглядеть наш код после изменений будет так:
static void Main(string[] args)
{
A a = new A("Hello");
var getMyProperty = GetFieldAccessor<A,string> ("_p");
//typed access via delegate
string result = getMyProperty(a);
Console.WriteLine(result);
Console.ReadLine();
}
public static Func<T, R> GetFieldAccessor<T, R>(string fieldName)
{
ParameterExpression param =
Expression.Parameter(typeof(T), "arg");
MemberExpression member =
Expression.Field(param, fieldName);
Func<T, R> compiled = Expression.Lambda<Func<T, R>>(member, param).Compile();
return compiled;
}
Результат:
Hello
Довольно элегантный способ получения private
поля
через делегат, не правда ли?
К сожалению, магии не
бывает, и от рефлексии никуда не деться в данном случае,
просто всю логику вместо нас берет .NET
Framework.
Для того чтобы убедиться в том, что мистики никакой нет, посмотрим на то, как
функция Field
реализована
в самом фреймворке.
/// <summary>
/// Creates a <see cref="MemberExpression"/> accessing a field.
/// </summary>
/// <param name="expression">The containing object of the field. This can be null for static fields.</param>
/// <param name="fieldName">The field to be accessed.</param>
/// <returns>The created <see cref="MemberExpression"/>.</returns>
public static MemberExpression Field(Expression expression, string fieldName)
{
RequiresCanRead(expression, "expression");
// bind to public names first
FieldInfo fi = expression.Type.GetField(fieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase | BindingFlags.FlattenHierarchy);
if (fi == null)
{
fi = expression.Type.GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.IgnoreCase | BindingFlags.FlattenHierarchy);
}
if (fi == null)
{
throw Error.InstanceFieldNotDefinedForType(fieldName, expression.Type);
}
return Expression.Field(expression, fi);
}
Как видим, из данного
кода мы пытаемся получить, по сути, дважды FieldInfo с
нашего типа данных. Мне очень нравится тот подход, который практикует компания Microsoft с
выкладыванием доступа к исходникам в онлайн-режиме. Посмотреть реализацию
той или иной функции можно очень детально. Это позволит более глубоко понять
предметную область.
GetActionType/GetDelegateType/GetFuncType
Метод GetDelegateType возвращает
объект Expression.Type
для
получения типа выражения и представляет generic Func и
Action
делегаты
с аргументами конкретного типа. Если обобщить, то это способ создать
динамически делегат, в котором GetDelegateType – это общая
реализация, GetActionType – реализация
для делегата типа Action, а GetFuncType
–
для типа Func.
Функция – это оболочка над функцией MakeDelegateType, которая
реализована не очень сложно, и достаточно легко можно понять реализации, если
посмотреть в исходный код (DelegateHelpers.Generated.cs).
internal static Type MakeDelegateType(Type[] types)
{
lock (_DelegateCache)
{
TypeInfo curTypeInfo = _DelegateCache;
// arguments & return type
for (int i = 0; i < types.Length; i++)
{
curTypeInfo = NextTypeInfo(types[i], curTypeInfo);
}
// see if we have the delegate already
if (curTypeInfo.DelegateType == null)
{
// clone because MakeCustomDelegate can hold onto the array.
curTypeInfo.DelegateType = MakeNewDelegate((Type[])types.Clone());
}
return curTypeInfo.DelegateType;
}
}
Давайте теперь рассмотрим, как это можно использовать. Для начала реализуем класс A,
в
который добавим один метод Method1,
с одним аргументом типа int.
public class A
{
public void Method1(int number)
{
Console.WriteLine(number);
}
}
Теперь попробуем получить наш метод Method1 с помощью функции GetDelegateType.
static void Main(string[] args)
{
A a = new A();
var method = typeof(A).GetMethod("Method1");
dynamic delegateType = GetDelegate(a, method);
delegateType(4);
Console.ReadLine();
}
private static Delegate GetDelegate(object target, MethodInfo method)
{
var tArgs = new List<Type>();
foreach (var param in method.GetParameters())
tArgs.Add(param.ParameterType);
tArgs.Add(method.ReturnType);
var delDecltype = Expression.GetDelegateType(tArgs.ToArray());
return Delegate.CreateDelegate(delDecltype, target, method);
}
Результат:
4
Метод GetActionType отличается от GetFunсType тем, что GetActionType возвращает тип void. Эти методы Microsoft реализовала
решением "в лоб" с помощью скрипта, написанного на питоне, если верить
комментариям.
internal static Type GetActionType(Type[] types)
{
switch (types.Length)
{
case 0: return typeof(Action);
#region Generated Delegate Action Types
// *** BEGIN GENERATED CODE ***
// generated by function: gen_delegate_action from: generate_dynsites.py
case 1: return typeof(Action<>).MakeGenericType(types);
case 2: return typeof(Action<,>).MakeGenericType(types);
case 3: return typeof(Action<,,>).MakeGenericType(types);
case 4: return typeof(Action<,,,>).MakeGenericType(types);
case 5: return typeof(Action<,,,,>).MakeGenericType(types);
case 6: return typeof(Action<,,,,,>).MakeGenericType(types);
case 7: return typeof(Action<,,,,,,>).MakeGenericType(types);
case 8: return typeof(Action<,,,,,,,>).MakeGenericType(types);
case 9: return typeof(Action<,,,,,,,,>).MakeGenericType(types);
case 10: return typeof(Action<,,,,,,,,,>).MakeGenericType(types);
case 11: return typeof(Action<,,,,,,,,,,>).MakeGenericType(types);
case 12: return typeof(Action<,,,,,,,,,,,>).MakeGenericType(types);
case 13: return typeof(Action<,,,,,,,,,,,,>).MakeGenericType(types);
case 14: return typeof(Action<,,,,,,,,,,,,,>).MakeGenericType(types);
case 15: return typeof(Action<,,,,,,,,,,,,,,>).MakeGenericType(types);
case 16: return typeof(Action<,,,,,,,,,,,,,,,>).MakeGenericType(types);
// *** END GENERATED CODE ***
#endregion
default: return null;
}
}
Реализация Func<> подобная этой, и вы
можете посмотреть ее здесь: GetFuncType.
Для того чтобы это использовать, давайте немного допилим наш метод GetDelegate с примера выше.
static void Main(string[] args)
{
A a = new A();
dynamic delegateType = GetDelegate<A>(a, "Method1");
delegateType(4);
Console.ReadLine();
}
private static Delegate GetDelegate<T>(object target, string methodName)
{
MethodInfo method = typeof(T).GetMethod(methodName);
List<Type> args = new List<Type>(
method.GetParameters().Select(p => p.ParameterType));
Type delegateType;
if (method.ReturnType == typeof(void))
{
delegateType = Expression.GetActionType(args.ToArray());
}
else
{
args.Add(method.ReturnType);
delegateType = Expression.GetFuncType(args.ToArray());
}
return Delegate.CreateDelegate(delegateType, target, method);
}
Результат:
4
Goto
Метод Expression.Goto
создает
выражение GotoExpression
и
представляет собой реализацию перехода с помощью goto.
Пример:
static void Main(string[] args)
{
LabelTarget label
= Expression.Label();
Expression
blockExpr = Expression.Block(
Expression.Call(
null,
typeof (Console).GetMethod("Write", new Type[] {typeof (String)}),
Expression.Constant("Hello
")
),
Expression.Goto(label),
Expression.Call(
null,
typeof (Console).GetMethod("Write", new Type[] {typeof (String)}),
Expression.Constant("World
")
),
Expression.Label(label)
);
Console.WriteLine(Expression.Lambda<Action>(blockExpr).Compile().DynamicInvoke());
Console.ReadLine();
}
Результат:
Hello
Слово "World" не будет выведено, поскольку
сразу же после первого вызова Call у нас срабатывает оператор перехода goto
для
перехода в конек блока дерева выражения.
GreaterThen/GreaterThenOrEqual
Метод Expression.GreaterThan
создает
BinaryExpression
для
сравнения чисел на больше (a
> b),
а метод Expression.GreaterThanOrEqual
позволяет
сравнить, больше или равно число a по отношению к числу b.
Пример:
static void Main(string[] args)
{
Expression.Constant(5),
Expression.Constant(4));
Expression greaterThenOrEqualExpr = Expression.GreaterThanOrEqual(
Expression.Constant(4),
Expression.Constant(4));
Console.WriteLine("GreateThen result {0}", Expression.Lambda<Func<bool>>(greaterThenExpr).Compile()());
Console.WriteLine("GreateThenOrEqual result {0}", Expression.Lambda<Func<bool>>(greaterThenOrEqualExpr).Compile()());
Console.ReadLine();
}
Результат:
GreateThen
result True
GreateThenOrEqual
result True
Небольшое пояснение. В первом случае у нас проходит
сравнение 5>4, а во втором 4>=4. Вроде, пока что нет ничего сложного.
IfThen/IfThenElse
Данные методы также
позволяют проверять условия с помощью оператора if – IfThen, и с помощью операторов if и
else – IfThenElse.
Пример для IfThen:
static void Main(string[] args)
{
ParameterExpression
value = Expression.Parameter(typeof(int), "value");
Expression
ifThenExpr = Expression.IfThen(
Expression.GreaterThan(value, Expression.Constant(4)),
Expression.Call(
null,
typeof(Console).GetMethod("WriteLine", new Type[] { typeof(String) }),
Expression.Constant("The
condition is true.")
)
);
Expression.Lambda<Action<int>>(ifThenExpr, new[]
{ value }).Compile()(5);
Console.ReadLine();
}
Результат:
The
condition is true.
В данном примере мы
передаем значение 5 как параметр и
проверяем условие 5>4. Приведенный выше пример можно переписать следующим
образом на языке C#:
int value = 5;
if (value > 4)
{
Console.WriteLine("The condition is true.");
}
Давайте сразу же
рассмотрим пример с IfThenElse.
Для этого приведенный выше пример мы расширим, добавив еще один аргумент для
блока else, а также сделаем так, чтобы
вывелся результат с блока else.
static void Main(string[] args)
{
ParameterExpression
value = Expression.Parameter(typeof(int), "value");
Expression
ifThenExpr = Expression.IfThenElse(
Expression.GreaterThan(value, Expression.Constant(4)),
Expression.Call(
null,
typeof(Console).GetMethod("WriteLine", new Type[] { typeof(String) }),
Expression.Constant("The
condition is true.")
),
Expression.Call(
null,
typeof(Console).GetMethod("WriteLine", new Type[] { typeof(String) }),
Expression.Constant("The
condition is false.")
)
);
Expression.Lambda<Action<int>>(ifThenExpr, new[]
{ value }).Compile()(3);
Console.ReadLine();
}
Результат:
The
condition is false.
Пример выше на языке C# можно переписать следующим
образом:
int value = 3;
if(value > 4)
Console.WriteLine("The condition is true.");
else
{
Console.WriteLine("The condition is false.");
}
Как говорится, все предельно просто.
Invoke
Метод Expression.Invoke
создает
InvocationExpression
для
вызова метода Invoke
для
делегатов или лямбда-выражений с передачей нужных аргументов. Если вы помните, как работают делегаты, то вы также, наверное, сможете вспомнить, как там используется метод Invoke. Прежде чем начать разбираться с деревьями выражений, рассмотрим простой пример на C#
с использованием метода Invoke
для
делегатов.
Func<int, int,
int>
sumFunc = (a, b) => a + b;
Console.WriteLine(sumFunc(3, 4)); //implicit call invoke method
Console.WriteLine(sumFunc.Invoke(3, 4)); //explicit call
invoke method
Как видим из
примера, у нас есть простой делегат, который суммирует два числа. В первом
случае мы не вызываем явно метод Invoke,
что
видно по коду, а во втором выводе на консоль вызываем. Теперь давайте этот же
пример перепишем на деревьях выражений.
Expression<Func<int, int, int>>
sumFuncExpr = (a, b) => a + b;
Expression invocationExpression =
Expression.Invoke(
sumFuncExpr,
Expression.Constant(3),
Expression.Constant(4));
Console.WriteLine(Expression.Lambda(invocationExpression).Compile().DynamicInvoke());
Результат:
7
IsTrue/IsFalse
Возвращает результат, который соответствует истине (IsTrue)
или ложности (IsFalse).
Пример:
static void Main(string[] args)
{
Expression
isTrueExpr =
Expression.IsTrue(
Expression.GreaterThan(Expression.Constant(5), Expression.Constant(4)));
Console.WriteLine(Expression.Lambda<Func<bool>>(isTrueExpr).Compile()());
Expression
isFalseExpr =
Expression.IsFalse(
Expression.GreaterThan(Expression.Constant(5), Expression.Constant(6)));
Console.WriteLine(Expression.Lambda<Func<bool>>(isFalseExpr).Compile()());
Console.ReadLine();
}
Результат:
True
True
Label
Создает LabelTarget,
которое создает метку, используемую для перехода с помощью метода goto. Ниже представлен простой
пример на языке C#
с использованием метки перехода совместно с оператором goto.
static void Main(string[] args)
{
int a = 5;
if (a > 4)
{
Console.WriteLine("Before
goto");
goto
b;
Console.WriteLine("After
goto");
}
b:
Console.WriteLine("Label
b");
Console.ReadLine();
}
На экране
будет выведен результат:
Before goto
Label b
Переписать этот код
через деревья выражений можно так:
static void Main(string[] args)
{
LabelTarget
returnTarget = Expression.Label("b");
BlockExpression
blockExpr =
Expression.Block(
Expression.IfThen(
Expression.GreaterThan(Expression.Constant(5), Expression.Constant(4)),
Expression.Block(
Expression.Call(typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }), Expression.Constant("Before
goto")),
Expression.Goto(returnTarget),
Expression.Call(typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }), Expression.Constant("After
goto")))
),
Expression.Label(returnTarget),
Expression.Call(typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }), Expression.Constant("Label
b"))
);
Expression.Lambda<Action>(blockExpr).Compile()();
Console.ReadLine();
}
Этот код
аналогичный коду, написанному перед этим, на простом C# синтаксисе без
использования возможностей expressions. А теперь вы увидели все то же самое, только через деревья выражений.
Lambda
Expression.Lambda
создает дерево выражений, которое представляет собой лямбда-выражение. До этого
в каждом примере мы уже использовали лямбда-выражения для вывода значения на
экран. Сейчас просто напишем простой пример, чтобы долго на этом не останавливаться.
Пример:
static void Main(string[] args)
{
ParameterExpression
param = Expression.Parameter(typeof(int), "arg");
// Creating an expression for the method call and specifying its
parameter.
MethodCallExpression
methodCall = Expression.Call(
typeof(Console).GetMethod("WriteLine", new Type[] { typeof(int) }),
param
);
// Compiling and invoking the methodCall expression.
Expression.Lambda<Action<int>>(
methodCall,
new ParameterExpression[] { param }
).Compile()(10);
Console.ReadLine();
}
Результат:
10
В данном примере мы с
помощью метода Console.WriteLine выводим
на консоль переданное значение.
LeftShift/LeftShiftAssign
Метод Expression.LeftShift
создает
BinaryExpression,
представляющий побитовую операцию со сдвигом влево. Метод LeftShiftAssign аналогичен
методу LeftShift,
за
исключением того, что мы можем сохранить результат побитового сдвига в
переменную.
Пример в таблице, как
это работает:
Мы сдвинули значение
14 на два бита влево и получили значение 56, что и показано в таблице выше.
Если вы обратили
внимание, то операции сдвига влево равносильно умножению на 2 для каждого шага.
Теперь можно перейти к самому примеру, так как мы разобрали, что такое побитовый
сдвиг влево.
Пример:
static void Main(string[] args)
{
Expression
leftShiftExpt = Expression.LeftShift(Expression.Constant(14), Expression.Constant(2));
Console.WriteLine(Expression.Lambda<Func<int>>(leftShiftExpt).Compile()());
Console.ReadLine();
}
Результат:
56
LessThan/LessThanOrEqual
Метод LessThan позволяет
проводить сравнение чисел на значение "меньше чем", а метод LessThanOrEqual – на "меньше или равно" определенного значения.
Давайте возьмем пример, который мы приводили для функций GreaterThan
и
GreaterThanOrEqual, и просто заменим на функции, которые изучаем сейчас.
Пример:
static void Main(string[] args)
{
Expression
lessThanExpr = Expression.LessThan(
Expression.Constant(5),
Expression.Constant(4));
Expression.Constant(4),
Expression.Constant(4));
Console.WriteLine("LessThan result {0}", Expression.Lambda<Func<bool>>(lessThanExpr).Compile()());
Console.WriteLine("LessThanOrEqual result {0}", Expression.Lambda<Func<bool>>(lessThanOrEqualExpr).Compile()());
Console.ReadLine();
}
Результат:
LessThan
result False
LessThanOrEqual
result True
ListInit
Метод Expression.ListInit – для того чтобы заполнить коллекцию с помощью Expression.ElementInit. Пример, как это выглядит в
языке C#, без использования деревьев выражений.
var list = new List<string>();
list.Add("Result1");
list.Add("Result2");
Теперь то же самое
сделаем с помощью деревьев выражений.
Пример:
static void Main(string[] args)
{
MethodInfo
addMethod = typeof(List<string>).GetMethod("Add");
ElementInit
elementInit1 =
Expression.ElementInit(
addMethod,
Expression.Constant("Result1"));
ElementInit
elementInit2 =
Expression.ElementInit(
addMethod,
Expression.Constant("Result2"));
NewExpression newListExpression
=
Expression.New(typeof(List<string>));
ListInitExpression
listInitExpression =
Expression.ListInit(
newListExpression,
elementInit1,
elementInit2);
Console.WriteLine(listInitExpression.ToString());
Console.ReadLine();
}
Результат:
new
List`1() {Void Add(System.String)("Result1"), Void
Add(System.String)("Resul
t2")}
Примечание. В
документации перед методом ListInit
идет
метод Expression.ListBind,
который позволяет заменить какое-то значение с коллекции. Но поскольку в того
же списка для изменения какого-то элемента есть только индексатор, я так и не
смог придумать, как использовать этот метод. Примеров в интернете мне не удалось
найти для данного случая, поэтому был вынужден пропустить использование этого
метода.
Loop
Создает объект LoopExpression,
представляющий собой бесконечный цикл, который может быть прерван с помощью
оператора break.
Пример:
static void Main(string[] args)
{
ParameterExpression
value = Expression.Parameter(typeof(int), "value");
// Creating an expression to hold a local variable.
ParameterExpression
result = Expression.Parameter(typeof(int), "result");
// Creating a label to jump to from a loop.
LabelTarget label
= Expression.Label(typeof(int));
// Creating a method body.
BlockExpression
block = Expression.Block(
new[]
{ result },
Expression.Assign(result, Expression.Constant(1)),
Expression.Loop(
Expression.IfThenElse(
Expression.GreaterThan(value, Expression.Constant(1)),
Expression.MultiplyAssign(result,
Expression.PostDecrementAssign(value)),
Expression.Break(label, result)
),
label
)
);
// Compile and run an expression tree.
int factorial = Expression.Lambda<Func<int,
int>>(block,
value).Compile()(5);
Console.WriteLine(factorial);
Console.ReadLine();
}
Результат:
120
MakeBinary
Создает BinaryExpression, содержащий бинарный
оператор. Эта функция базовая, чтобы не использовать по отдельности
функции по работе с BinaryExpression.
Мы уже до этого с вами рассмотрели использование функций Add, And, AddChecked и т.д. Для них Microsoft реализовала высокоуровневую
оболочку.
public static BinaryExpression MakeBinary(ExpressionType binaryType, Expression left, Expression right, bool
liftToNull, MethodInfo method, LambdaExpression conversion)
{
switch (binaryType)
{
case ExpressionType.Add:
return Add(left,
right, method);
case ExpressionType.AddChecked:
return AddChecked(left, right, method);
case ExpressionType.Subtract:
return Subtract(left, right, method);
case ExpressionType.SubtractChecked:
return SubtractChecked(left, right, method);
case ExpressionType.Multiply:
return Multiply(left, right, method);
case ExpressionType.MultiplyChecked:
return MultiplyChecked(left, right, method);
case ExpressionType.Divide:
return Divide(left, right, method);
case ExpressionType.Modulo:
return Modulo(left, right, method);
case ExpressionType.Power:
return Power(left, right, method);
case ExpressionType.And:
return And(left,
right, method);
case ExpressionType.AndAlso:
return AndAlso(left, right, method);
case ExpressionType.Or:
return Or(left,
right, method);
case ExpressionType.OrElse:
return OrElse(left, right, method);
case ExpressionType.LessThan:
return LessThan(left, right, liftToNull, method);
case ExpressionType.LessThanOrEqual:
return LessThanOrEqual(left, right, liftToNull, method);
case ExpressionType.GreaterThan:
return GreaterThan(left, right, liftToNull, method);
case ExpressionType.GreaterThanOrEqual:
return GreaterThanOrEqual(left, right, liftToNull, method);
case ExpressionType.Equal:
return Equal(left, right, liftToNull, method);
case ExpressionType.NotEqual:
return NotEqual(left, right, liftToNull, method);
case ExpressionType.ExclusiveOr:
return ExclusiveOr(left, right, method);
case ExpressionType.Coalesce:
return Coalesce(left, right, conversion);
case ExpressionType.ArrayIndex:
return ArrayIndex(left, right);
case ExpressionType.RightShift:
return RightShift(left, right, method);
case ExpressionType.LeftShift:
return LeftShift(left, right, method);
case ExpressionType.Assign:
return Assign(left, right);
case ExpressionType.AddAssign:
return AddAssign(left, right, method, conversion);
case ExpressionType.AndAssign:
return AndAssign(left, right, method, conversion);
case ExpressionType.DivideAssign:
return DivideAssign(left, right, method, conversion);
case ExpressionType.ExclusiveOrAssign:
return ExclusiveOrAssign(left, right, method, conversion);
case ExpressionType.LeftShiftAssign:
return LeftShiftAssign(left, right, method, conversion);
case ExpressionType.ModuloAssign:
return ModuloAssign(left, right, method, conversion);
case ExpressionType.MultiplyAssign:
return MultiplyAssign(left, right, method, conversion);
case ExpressionType.OrAssign:
return OrAssign(left, right, method, conversion);
case ExpressionType.PowerAssign:
return PowerAssign(left, right, method, conversion);
case ExpressionType.RightShiftAssign:
return RightShiftAssign(left, right, method, conversion);
case ExpressionType.SubtractAssign:
return SubtractAssign(left, right, method, conversion);
case ExpressionType.AddAssignChecked:
return AddAssignChecked(left,
right, method, conversion);
case ExpressionType.SubtractAssignChecked:
return SubtractAssignChecked(left, right, method, conversion);
case ExpressionType.MultiplyAssignChecked:
return MultiplyAssignChecked(left, right, method, conversion);
default:
throw Error.UnhandledBinary(binaryType);
}
}
Пример:
static void Main(string[] args)
{
Expression
makeBinaryExpr = Expression.MakeBinary(ExpressionType.Add,
Expression.Constant(4),
Expression.Constant(2));
Console.WriteLine(Expression.Lambda<Func<int>>(makeBinaryExpr).Compile()());
Console.ReadLine();
}
Результат:
6
На этой позитивной
ноте мы завершим данную статью. В следующей части темы рассмотрим такие операции, как умножение, преинкрементные и постинкрементные операции и многое другое.
No comments:
Post a Comment