C# 这是MiscUtils中的错误吗?

C# 这是MiscUtils中的错误吗?,c#,miscutils,C#,Miscutils,这是MiscUtils中的错误还是我遗漏了什么 decimal a = (1M/30); int b = 59; Assert.AreEqual(a*b, Operator.MultiplyAlternative(a, b)); Assert.AreEqual(b*a, Operator.MultiplyAlternative(b, a)); 在最后一行失败: expected: <1.9666666666666666666666666647> but was: <0>

这是MiscUtils中的错误还是我遗漏了什么

decimal a = (1M/30);
int b = 59;
Assert.AreEqual(a*b, Operator.MultiplyAlternative(a, b));
Assert.AreEqual(b*a, Operator.MultiplyAlternative(b, a));
在最后一行失败:

expected: <1.9666666666666666666666666647>
 but was: <0>
因此,第二个断言需要重写:

Assert.AreEqual((int)(b*a), Operator.MultiplyAlternative(b, a));
现在两种说法都成功了。与前面一样,根据参数的顺序,将返回不同的结果,但现在第二次调用将生成逻辑正确的结果。

根据,方法签名如下所示:

if (castArgsToResultOnFailure && !(         // if we show retry                                                        
        typeof(TArg1) == typeof(TResult) &&  // and the args aren't
        typeof(TArg2) == typeof(TResult)))
{ // already "TValue, TValue, TValue"...
    var ltc = Type.GetTypeCode(lhs.Type);
    var rtc = Type.GetTypeCode(rhs.Type);
    // Use the higher precision element
    if (ltc > rtc)
    {
        // TArg1/TResult is higher precision than TArg2. Simply lift rhs
        var castRhs = Expression.Convert(rhs, lhs.Type);
        return
            Expression.Lambda<Func<TArg1, TArg2, TResult>>(body(lhs, castRhs), lhs, rhs).Compile();
    }
    // TArg2 is higher precision than TArg1/TResult. Lift lhs and Cast result
    var castLhs = Expression.Convert(lhs, rhs.Type);
    var castResult = Expression.Convert(body(castLhs, rhs), lhs.Type);
    return Expression.Lambda<Func<TArg1, TArg2, TResult>>(castResult, lhs, rhs).Compile();
}
public static TArg1 MultiplyAlternative<TArg1, TArg2>(TArg1 value1, TArg2 value2)
你看,
Expression.Lambda(body(lhs,rhs),lhs,rhs).Compile()int
decimal
TArg1
TArg2
的任何组合,code>都会失败(例如,如果将
decimal
更改为
double
,它实际上具有相同的行为,因此它不仅会受到
decimal
的影响),然后,
catch
块试图将这两个参数强制转换为
TResult
类型,而这又取决于参数顺序。所以在第一种情况下,所有的
decimal
cast都被转换,在第二种情况下,所有的
int
cast都被转换


不幸的是,我无法回答为什么这个lambda编译会失败,它是一个bug还是一个语言限制。

C#这类东西太糟糕了。我使用这个库,它很棒,但不幸的是它不能解决所有的语言缺陷。是的,它是一个很棒的小库。但这件事让我大吃一惊,我不明白。如果TArg2是十进制的,为什么会强制为(int)0?在您的注释中添加了更多详细信息。谢谢你的帮助。
/// <summary>
/// Create a function delegate representing a binary operation
/// </summary>
/// <param name="castArgsToResultOnFailure">
/// If no matching operation is possible, attempt to convert
/// TArg1 and TArg2 to TResult for a match? For example, there is no
/// "decimal operator /(decimal, int)", but by converting TArg2 (int) to
/// TResult (decimal) a match is found.
/// </param>
/// <typeparam name="TArg1">The first parameter type</typeparam>
/// <typeparam name="TArg2">The second parameter type</typeparam>
/// <typeparam name="TResult">The return type</typeparam>
/// <param name="body">Body factory</param>
/// <returns>Compiled function delegate</returns>
public static Func<TArg1, TArg2, TResult> CreateExpression<TArg1, TArg2, TResult>(
        Func<Expression, Expression, BinaryExpression> body, bool castArgsToResultOnFailure)
{
    ParameterExpression lhs = Expression.Parameter(typeof(TArg1), "lhs");
    ParameterExpression rhs = Expression.Parameter(typeof(TArg2), "rhs");
    try
    {
        try
        {
            return Expression.Lambda<Func<TArg1, TArg2, TResult>>(body(lhs, rhs), lhs, rhs).Compile();
        }
        catch (InvalidOperationException)
        {
            if (castArgsToResultOnFailure && !(         // if we show retry
                            typeof(TArg1) == typeof(TResult) &&  // and the args aren't
                            typeof(TArg2) == typeof(TResult)))
            { // already "TValue, TValue, TValue"...
                // convert both lhs and rhs to TResult (as appropriate)
                Expression castLhs = typeof(TArg1) == typeof(TResult) ?
                                (Expression)lhs :
                                (Expression)Expression.Convert(lhs, typeof(TResult));
                Expression castRhs = typeof(TArg2) == typeof(TResult) ?
                                (Expression)rhs :
                                (Expression)Expression.Convert(rhs, typeof(TResult));

                return Expression.Lambda<Func<TArg1, TArg2, TResult>>(
                        body(castLhs, castRhs), lhs, rhs).Compile();
            }
            else throw;
        }
    }
    catch (Exception ex)
    {
        string msg = ex.Message; // avoid capture of ex itself
        return delegate { throw new InvalidOperationException(msg); };
    }
}