首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >设置任何Func<>的参数

设置任何Func<>的参数
EN

Stack Overflow用户
提问于 2020-04-19 11:21:31
回答 2查看 173关注 0票数 1

我有一个func<>,Func<,>,func<,>.我想用一个常量替换一个输入参数。

例:

代码语言:javascript
复制
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)"

现在我已经知道了如何获得结果函数的类型,但这并不能真正帮助我实现所需的行为:

代码语言:javascript
复制
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");
}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-04-19 13:11:43

以防万一你需要使用表达式树构建函数

代码语言:javascript
复制
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;
}

要使用此方法:

代码语言:javascript
复制
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"));
票数 0
EN

Stack Overflow用户

发布于 2020-04-19 11:47:22

不太清楚你的转换的目的是什么,但它不是更容易避免所有的反射。例如:

代码语言:javascript
复制
Func<int, string, string> func3 = (a, b) => a.ToString() + b;

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

由于您所讨论的范围非常有限(只支持Func<TReturn>Func<T1, TReturn>Func<T1, T2, TReturn>),通过反射进行此操作更容易出错,也更难阅读。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/61303483

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档