Note that there are some explanatory texts on larger screens.

plurals
  1. POIs this a bug in MiscUtils?
    primarykey
    data
    text
    <p>Is this a bug in MiscUtils or am I missing something?</p> <pre><code>decimal a = (1M/30); int b = 59; Assert.AreEqual(a*b, Operator.MultiplyAlternative(a, b)); Assert.AreEqual(b*a, Operator.MultiplyAlternative(b, a)); </code></pre> <p>Fails on the last line:</p> <pre><code>expected: &lt;1.9666666666666666666666666647&gt; but was: &lt;0&gt; </code></pre> <h3>Update</h3> <p>As Petr pointed out there is some coercion going on in the CreateExpression method which is causing the problem. When using the compiler we don't see such issues because the parameters are lifted to the type with the highest precision, which also becomes the return type. </p> <p>The second 'Assert' should have failed anyway, because if consistent with normal C# behaviour, I would expect it to lift the first parameter (b) to a <code>decimal</code> and perform the operation. Normally, if we wanted to store the result to a variable of a type with lower precision we would need to do an explicit cast. However, since the method we are calling has a return type that may be of lower precision and the caller has explicitly invoked the method that returns a lower precision result - it seems justifiable to automatically perform a potentially truncating cast as part of the operation. In other words the expected result from the second expression would be <code>1</code>.</p> <p>So, we can change CreateExpression to reflect that behaviour as follows:</p> <pre><code>if (castArgsToResultOnFailure &amp;&amp; !( // if we show retry typeof(TArg1) == typeof(TResult) &amp;&amp; // 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 &gt; rtc) { // TArg1/TResult is higher precision than TArg2. Simply lift rhs var castRhs = Expression.Convert(rhs, lhs.Type); return Expression.Lambda&lt;Func&lt;TArg1, TArg2, TResult&gt;&gt;(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&lt;Func&lt;TArg1, TArg2, TResult&gt;&gt;(castResult, lhs, rhs).Compile(); } </code></pre> <p>The second assertion therefore needs to be rewritten:</p> <pre><code>Assert.AreEqual((int)(b*a), Operator.MultiplyAlternative(b, a)); </code></pre> <p>Now both assertions succeed. As before, depending on the order of the parameters, different results will be returned, but now the second invocation produces a result that is logically correct.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload