gpt4 book ai didi

c# - 使用 Expression 到 'Cast' Func 到 Func

转载 作者:行者123 更新时间:2023-11-30 22:17:44 31 4
gpt4 key购买 nike

我写了一个小函数,试图动态地执行以下操作:

        Func<object, object> fa = i => Convert.ChangeType(i, typeof (string));
Func<int, string> fb = o => (string) fa((int)o);

函数如下:

    /// <summary>
/// Converts <see cref="Func{object, object}" /> to <see cref="Func{T, TResult}" />.
/// </summary>
public static Delegate Convert(Func<object, object> func, Type argType, Type resultType)
{
Contract.Requires(func != null);
Contract.Requires(resultType != null);

var param = Expression.Parameter(argType);

var converted = Expression.Convert(
Expression.Call(func.Method, Expression.Convert(param, typeof (object))),
resultType);

var delegateType = typeof (Func<,>).MakeGenericType(argType, resultType);
return Expression.Lambda(delegateType, converted, param).Compile();
}

现在这在不涉及闭包的情况下工作正常 - 这个测试通过了:

    [Test]
public void When_Converting_Without_Closure_Then_Suceeds()
{
// Arrange
Func<object, object> f = i => Convert.ChangeType(i, typeof(string));
var sut = FuncConversion.Convert(f, typeof(int), typeof(string));

// Act
var res = (string) sut.DynamicInvoke(10);

// Assert
Assert.AreEqual(typeof(Func<int, string>), sut.GetType());
Assert.AreEqual("10", res);
}

但是当涉及到闭包时,这个测试失败了:

    [Test]
public void When_Converting_With_Closure_Then_Succeeds()
{
// Arrange
var typeTo = typeof (string);
Func<object, object> f = i => Convert.ChangeType(i, typeTo);
var sut = FuncConversion.Convert(f, typeof(int), typeof(string));

// Act
var res = (string)sut.DynamicInvoke(10);

// Assert
Assert.AreEqual(typeof(Func<int, string>), sut.GetType());
Assert.AreEqual("10", res);
}

System.ArgumentException : 静态方法需要空实例,非静态方法需要非空实例。参数名称:方​​法 在 System.Linq.Expressions.Expression.ValidateStaticOrInstanceMethod(表达式实例,MethodInfo 方法) 在 System.Linq.Expressions.Expression.Call(MethodInfo 方法,表达式 arg0)

知道哪里出了问题吗?

最佳答案

确定了。问题是对于闭包,通常是静态方法的 func 有它的第一个参数,它将是实例方法的目标实例,用于保存闭包状态。所以我需要检查该状态是否存在,如果存在则调用它。

等等:

    /// <summary>
/// Converts <see cref="Func{object, object}" /> to <see cref="Func{T, TResult}" />.
/// </summary>
public static Delegate Convert(Func<object, object> func, Type argType, Type resultType)
{
// If we need more versions of func then consider using params Type as we can abstract some of the
// conversion then.

Contract.Requires(func != null);
Contract.Requires(resultType != null);

var param = Expression.Parameter(argType);
var convertedParam = new Expression[] {Expression.Convert(param, typeof (object))};

// This is gnarly... If a func contains a closure, then even though its static, its first
// param is used to carry the closure, so its as if it is not a static method, so we need
// to check for that param and call the func with it if it has one...
Expression call;
call = Expression.Convert(
func.Target == null
? Expression.Call(func.Method, convertedParam)
: Expression.Call(Expression.Constant(func.Target), func.Method, convertedParam), resultType);

var delegateType = typeof (Func<,>).MakeGenericType(argType, resultType);
return Expression.Lambda(delegateType, call, param).Compile();
}

关于c# - 使用 Expression 到 'Cast' Func<object, object> 到 Func<T, TRet>,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16590685/

31 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com