تعيين في .NET Framework 3.5 أشجار التعبير
-
03-07-2019 - |
سؤال
هل من الممكن لترميز مهمة في شجرة التعبير؟
المحلول
لا، لا أعتقد ذلك.
وبالتأكيد C # مترجم يرفض ذلك عند تحويل التعبير امدا:
int x;
Expression<Func<int,int>> foo = (x=y); // Assign to x and return value
وهذا ينتج الخطأ:
CS0832: An expression tree may not contain an assignment operator
نصائح أخرى
ويجب عليك قادرة على القيام بذلك مع NET 4.0 مكتبة. بواسطة Microsoft.Scripting.Core.dll الاستيراد للمشروع. NET 3.5 الخاص بك.
وأستخدمه DLR 0.9 - قد يكون هناك بعض التغيير على Expession.Block وExpression.Scope في الإصدار 1.0 (يمكنك أن ترى إشارة من <لأ href = "http://www.codeplex.com/dlr/Thread/ View.aspx؟ رقم الموضوع = 43234 "يختلط =" noreferrer "> http://www.codeplex.com/dlr/Thread/View.aspx؟ThreadId=43234 )
وبعد العينة لتظهر لك.
using System;
using System.Collections.Generic;
using Microsoft.Scripting.Ast;
using Microsoft.Linq.Expressions;
using System.Reflection;
namespace dlr_sample
{
class Program
{
static void Main(string[] args)
{
List<Expression> statements = new List<Expression>();
ParameterExpression x = Expression.Variable(typeof(int), "r");
ParameterExpression y = Expression.Variable(typeof(int), "y");
statements.Add(
Expression.Assign(
x,
Expression.Constant(1)
)
);
statements.Add(
Expression.Assign(
y,
x
)
);
MethodInfo cw = typeof(Console).GetMethod("WriteLine", new Type[] { typeof(int) });
statements.Add(
Expression.Call(
cw,
y
)
);
LambdaExpression lambda = Expression.Lambda(Expression.Scope(Expression.Block(statements), x, y));
lambda.Compile().DynamicInvoke();
Console.ReadLine();
}
}
}
ولي طريقة التمديد لتفعل بالضبط هذا:
/// <summary>
/// Provides extensions for converting lambda functions into assignment actions
/// </summary>
public static class ExpressionExtenstions
{
/// <summary>
/// Converts a field/property retrieve expression into a field/property assign expression
/// </summary>
/// <typeparam name="TInstance">The type of the instance.</typeparam>
/// <typeparam name="TProp">The type of the prop.</typeparam>
/// <param name="fieldGetter">The field getter.</param>
/// <returns></returns>
public static Expression<Action<TInstance, TProp>> ToFieldAssignExpression<TInstance, TProp>
(
this Expression<Func<TInstance, TProp>> fieldGetter
)
{
if (fieldGetter == null)
throw new ArgumentNullException("fieldGetter");
if (fieldGetter.Parameters.Count != 1 || !(fieldGetter.Body is MemberExpression))
throw new ArgumentException(
@"Input expression must be a single parameter field getter, e.g. g => g._fieldToSet or function(g) g._fieldToSet");
var parms = new[]
{
fieldGetter.Parameters[0],
Expression.Parameter(typeof (TProp), "value")
};
Expression body = Expression.Call(AssignmentHelper<TProp>.MethodInfoSetValue,
new[] {fieldGetter.Body, parms[1]});
return Expression.Lambda<Action<TInstance, TProp>>(body, parms);
}
public static Action<TInstance, TProp> ToFieldAssignment<TInstance, TProp>
(
this Expression<Func<TInstance, TProp>> fieldGetter
)
{
return fieldGetter.ToFieldAssignExpression().Compile();
}
#region Nested type: AssignmentHelper
private class AssignmentHelper<T>
{
internal static readonly MethodInfo MethodInfoSetValue =
typeof (AssignmentHelper<T>).GetMethod("SetValue", BindingFlags.NonPublic | BindingFlags.Static);
private static void SetValue(ref T target, T value)
{
target = value;
}
}
#endregion
}
وكما قال جون السكيت وTraumaPony بالفعل، Expression.Assign
غير متوفر قبل. NET 4. وفيما يلي مثال ملموس آخر على كيفية التغلب على هذا الشيء المفقود:
public static class AssignmentExpression
{
public static Expression Create(Expression left, Expression right)
{
return
Expression.Call(
null,
typeof(AssignmentExpression)
.GetMethod("AssignTo", BindingFlags.NonPublic | BindingFlags.Static)
.MakeGenericMethod(left.Type),
left,
right);
}
private static void AssignTo<T>(ref T left, T right) // note the 'ref', which is
{ // important when assigning
left = right; // to value types!
}
}
وبعد ذلك مجرد دعوة AssignmentExpression.Create()
في مكان Expression.Assign()
.
وربما يمكن أن تغلب عليه nexting أشجار التعبير. استدعاء دالة امدا، حيث حجة هي قيمة المحال إليه.