كيف يمكنني تجميع شجرة التعبير إلى أسلوب استدعاء، C #؟

StackOverflow https://stackoverflow.com/questions/346523

  •  19-08-2019
  •  | 
  •  

سؤال

ولدي شجرة التعبير لقد خلق عن طريق تحليل أكس باستخدام فئة التعبير في C #. انظر هذا السؤال .

وليس لدي سوى إضافة، طرح، قسمة، ضرب، معلمات، ووأو في شجرة التعبير بلدي. هل هناك طريقة لتحويل هذا ExpressionTree إلى أسلوب استدعاء؟ ... أو هل يجب أن تنبعث منها IL يدويا؟

مع أطيب التحيات،

هل كانت مفيدة؟

المحلول

وهنا مثال من كلا النهجين. إذا كنت قد غاب عن شيء، أو إذا كنت تريد المزيد من المعلومات، فقط اسمحوا لي أن أعرف.

static void Main()
{
    // try to do "x + (3 * x)"

    var single = BuildSingle<decimal>();
    var composite = BuildComposite<decimal>();

    Console.WriteLine("{0} vs {1}", single(13.2M), composite(13.2M));
}
// utility method to get the 3 as the correct type, since there is not always a "int x T"
static Expression ConvertConstant<TSource, TDestination>(TSource value)
{
    return Expression.Convert(Expression.Constant(value, typeof(TSource)), typeof(TDestination));
}
// option 1: a single expression tree; this is the most efficient
static Func<T,T> BuildSingle<T>()
{        
    var param = Expression.Parameter(typeof(T), "x");
    Expression body = Expression.Add(param, Expression.Multiply(
        ConvertConstant<int, T>(3), param));
    var lambda = Expression.Lambda<Func<T, T>>(body, param);
    return lambda.Compile();
}
// option 2: nested expression trees:
static Func<T, T> BuildComposite<T>()
{

    // step 1: do the multiply:
    var paramInner = Expression.Parameter(typeof(T), "inner");
    Expression bodyInner = Expression.Multiply(
        ConvertConstant<int, T>(3), paramInner);
    var lambdaInner = Expression.Lambda(bodyInner, paramInner);

    // step 2: do the add, invoking the existing tree
    var paramOuter = Expression.Parameter(typeof(T), "outer");
    Expression bodyOuter = Expression.Add(paramOuter, Expression.Invoke(lambdaInner, paramOuter));
    var lambdaOuter = Expression.Lambda<Func<T, T>>(bodyOuter, paramOuter);

    return lambdaOuter.Compile();
}

وشخصيا، وأود أن تهدف نحو الطريقة الأولى. انها على حد سواء أسهل وأكثر كفاءة. قد ينطوي هذا على تمرير المعلمة الأصلية في جميع أنحاء كومة من التعليمات البرمجية المتداخلة، ولكن فليكن ذلك. لقد حصلت بعض التعليمات البرمجية في مكان ما أن يأخذ نهج "استدعاء" (المركبة)، وإعادة يكتب-الشجرة باعتبارها النهج الأول (واحد) - ولكن ما هو معقد جدا وطويلة. ولكنها مفيدة جدا لإطار الكيان (والذي لا يعتمد Expression.Invoke).

نصائح أخرى

وتحتاج إلى إنشاء امدا -. أي بمعنى

var lambda = Expression.Lambda<Func<float,int>>(body, param);
Func<float,int> method = lambda.Compile();
int v = method(1.0); // test

وحيث "الهيئة" الخاص بك هو شجرة التعبير (مع تعويم، والعودة عدد صحيح) التي تنطوي على المعلمة ParameterExpression.

وقد تجد أيضا هذا و <لأ href = "HTTP: / /marcgravell.blogspot.com/2008/10/express-yourself.html "يختلط =" noreferrer "> هذا مفيدة.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top