簡體   English   中英

在 C# 中定義一個泛型 lambda 並將其賦值給一個變量,以便與 MakeGenericMethod 一起使用

[英]Define a generic lambda in C# and assign it to a variable to be used with MakeGenericMethod

我知道我可以定義一個通用的 function,然后借助反射使用 Type 參數調用它。 像這樣的東西:

private static void SomeFunc<Tf>()
{
    // Something type safe against Tf
}

public void CallingFunc()
{
    var someType = typeof(whatever); // This may be retrieved using reflection as well instead
    var someMethod = this.GetType().GetMethod(nameof(SomeFunc)), BindingFlags.Static | BindingFlags.NonPublic);
    var typedMethod = someMethod.MakeGenericMethod(someType);
    typedMethod.Invoke(null, null);
}

現在,有沒有辦法將此SomeMethod<Tf>()內聯聲明為 lambda,以避免將其聲明為 class 中的單獨方法,但仍然能夠將其與MakeGenericMethod一起使用? 就像是:

public void CallingFunc()
{
    var someType = typeof(whatever); // This may be retrieved using reflection as well instead

    // This obviously doesn't work as it requires Tf to be known at this stage, and we can have Tf only as a Type variable here => what should I do instead?
    var someMethod = new Action<Tf>(() => /* Something type safe against Tf */).Method;

    var typedMethod = someMethod.MakeGenericMethod(someType);
    typedMethod.Invoke(null, null);
}

使CallingFunc通用化也不是一個選項 - someType變量是通過反射檢索的,因此在編譯時是未知的。

基於: https://gist.github.com/afreeland/6733381謝謝!

稍作改進:

public class ExpressionBuilder { // 定義我們的一些默認過濾選項 private static MethodInfo containsMethod = typeof(string).GetMethod("Contains", new[] { typeof(string) }); 私有 static MethodInfo startsWithMethod = typeof(string).GetMethod("StartsWith", new[] { typeof(string) }); 私有 static MethodInfo endsWithMethod = typeof(string).GetMethod("EndsWith", new[] { typeof(string) }); public static Expression<Func<T, bool>> GetExpression(List<GridHelper.Filter> filters) { // #KickIT 中沒有傳遞過濾器 if (filters.Count == 0) return null;

        // Create the parameter for the ObjectType (typically the 'x' in your expression (x => 'x')
        // The "parm" string is used strictly for debugging purposes
        ParameterExpression param = Expression.Parameter(typeof(T), "parm");

        // Store the result of a calculated Expression
        Expression exp = null;

        if (filters.Count == 1)
            exp = GetExpression<T>(param, filters[0]); // Create expression from a single instance
        else if (filters.Count == 2)
            exp = GetExpression<T>(param, filters[0], filters[1]); // Create expression that utilizes AndAlso mentality
        else
        {
            // Loop through filters until we have created an expression for each
            while (filters.Count > 0)
            {
                // Grab initial filters remaining in our List
                var f1 = filters[0];
                var f2 = filters[1];

                // Check if we have already set our Expression
                if (exp == null)
                    exp = GetExpression<T>(param, filters[0], filters[1]); // First iteration through our filters
                else
                    exp = Expression.AndAlso(exp, GetExpression<T>(param, filters[0], filters[1])); // Add to our existing expression

                filters.Remove(f1);
                filters.Remove(f2);

                // Odd number, handle this seperately
                if (filters.Count == 1)
                {
                    // Pass in our existing expression and our newly created expression from our last remaining filter
                    exp = Expression.AndAlso(exp, GetExpression<T>(param, filters[0]));

                    // Remove filter to break out of while loop
                    filters.RemoveAt(0);
                }
            }
        }

        return Expression.Lambda<Func<T, bool>>(exp, param);
    }

    private static Expression GetExpression<T>(ParameterExpression param, GridHelper.Filter filter)
    {
        // The member you want to evaluate (x => x.FirstName)
        MemberExpression member = Expression.Property(param, filter.PropertyName);

        var typeOfValue = filter.Value.GetType();
        // The value you want to evaluate
        ConstantExpression constant = Expression.Constant(filter.Value, typeOfValue);


        // Determine how we want to apply the expression
        switch (filter.Operator)
        {
            case GridHelper.Operator.Equals:
                return Expression.Equal(member, constant);
            
            case GridHelper.Operator.NotEqual:
                return Expression.Equal(member, constant);

            case GridHelper.Operator.Contains:
                return Expression.Call(member, containsMethod, constant);

            case GridHelper.Operator.GreaterThan:
                return Expression.GreaterThan(member, constant);

            case GridHelper.Operator.GreaterThanOrEqual:
                return Expression.GreaterThanOrEqual(member, constant);

            case GridHelper.Operator.LessThan:
                return Expression.LessThan(member, constant);

            case GridHelper.Operator.LessThanOrEqualTo:
                return Expression.LessThanOrEqual(member, constant);

            case GridHelper.Operator.StartsWith:
                return Expression.Call(member, startsWithMethod, constant);

            case GridHelper.Operator.EndsWith:
                return Expression.Call(member, endsWithMethod, constant);

        }

        return null;
    }

    private static BinaryExpression GetExpression<T>(ParameterExpression param, GridHelper.Filter filter1, GridHelper.Filter filter2)
    {
        Expression result1 = GetExpression<T>(param, filter1);
        Expression result2 = GetExpression<T>(param, filter2);
        return Expression.AndAlso(result1, result2);
    }


}
// Filter class
public class GridHelper
{
    public enum Operator
    {
        Contains,
        GreaterThan,
        GreaterThanOrEqual,
        LessThan,
        LessThanOrEqualTo,
        StartsWith,
        EndsWith,
        Equals,
        NotEqual,
        Or
    }

    public class Filter
    {
        public string PropertyName { get; set; }
        public object? Value { get; set; }
        public Operator Operator { get; set; }
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM