简体   繁体   English

设置任意 Func<> 的参数

[英]Set parameter of any Func<>

I have an object of any of the func types func<>, Func<,>, func<,,>... And I'd like to replace one of the input parameters with a constant value.我有一个 object 的任何 func 类型 func<>, Func<,>, func<,,>... 我想用一个常量值替换其中一个输入参数。

eg:例如:

object SetParameter<T>(object function, int index, T value){
    //I don't know how to code this.
}

Func<int, String, String> function = (a, b) => a.ToString() + b;
object objectFunction = function;
object newFunction = SetParameter<int>(objectFunction, 0, 5);
// Here the new function should be a Func<String, String> which value "(b) => function(5, b)"

I already now how to get the type of the resulting function, but that does not really help me in implementing the desired behavior:我现在已经如何获取生成的 function 的类型,但这并不能真正帮助我实现所需的行为:

private Type GetNewFunctionType<T>(object originalFunction, int index, T value)
{
    Type genericType = originalFunction.GetType();

    if (genericType.IsGenericType)
    {
        var types = genericType.GetGenericArguments().ToList();
        types.RemoveAt(index);
        Type genericTypeDefinition = genericType.GetGenericTypeDefinition();
        return genericTypeDefinition.MakeGenericType(types.ToArray());
    }

    throw new InvalidOperationException($"{nameof(originalFunction)} must be a generic type");
}

It's not quite clear what the purpose of your conversion is for, but wouldn't it be easier to avoid all the reflection.目前尚不清楚转换的目的是什么,但避免所有反射不是更容易。 Eg:例如:

Func<int, string, string> func3 = (a, b) => a.ToString() + b;

Func<string, string> func3withConst = (b) => func3(10, b);

Since you are talking about a very limited scope (supporting just Func<TReturn> , Func<T1, TReturn> and Func<T1, T2, TReturn> ) doing this through reflection is much more error prone and harder to read.由于您谈论的是非常有限的 scope (仅支持Func<TReturn>Func<T1, TReturn>Func<T1, T2, TReturn> )通过反射执行此操作更容易出错且更难阅读。

Just in case you need to use expression tree to build the function :以防万一您需要使用表达式树来构建 function

object SetParameter<T>(object function, int index, T value)
{
    var parameterTypes = function.GetType().GetGenericArguments();

    // Skip where i == index
    var newFuncParameterTypes = parameterTypes.SkipWhile((_, i) => i == index).ToArray();

    // Let's assume function is Fun<,,> to make this example simple :)
    var newFuncType = typeof(Func<,>).MakeGenericType(newFuncParameterTypes);

    // Now build a new function using expression tree.
    var methodCallParameterTypes = parameterTypes.Reverse().Skip(1).Reverse().ToArray();
    var methodCallParameters = methodCallParameterTypes.Select(
        (t, i) => i == index
            ? (Expression)Expression.Constant(value, typeof(T))
            : Expression.Parameter(t, "b")
        ).ToArray();

    // func.Invoke(5, b)
    var callFunction = Expression.Invoke(
        Expression.Constant(function),
        methodCallParameters);

    // b => func.Invoke(5, b)
    var newFunc = Expression.Lambda(
        newFuncType,
        callFunction,
        methodCallParameters.OfType<ParameterExpression>()
    ).Compile();

    return newFunc;
}

To use this:要使用这个:

Func<int, string, string> func = (a, b) => a.ToString() + b;

var newFunc = (Func<string, string>)SetParameter<int>(func, 0, 5);

// Output: 5b
Console.WriteLine(newFunc("b"));

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM