4

我使用MiscUtil Operators 一段时间没有任何大问题。但是现在我发现了一些真正困扰我的事情:

byte first = 13;
byte second = 29;

byte result = MiscUtil.Operator.Add(first, second);

这个等式的简单预期结果应该是result == 42,但不幸的是,这会引发InvalidOperationException

The binary operator Add is not defined for the types 'System.Byte' and 'System.Byte'.

通过仔细观察这种奇怪的行为,您会发现System.Byte实际上并没有实现这些运算符。在 C# 中,这些类型将被隐式转换为 anInt32并且确实实现了这些运算符。

所以现在的问题是:有没有机会让 MiscUtil 与byteand一起工作sbyte

4

2 回答 2

5

从技术上讲,intetc没有实现这些运算符。它们不是由正常意义上的“操作员”提供的(这将涉及 static- call),而是直接由add操作码表示。最终,这种情况下的失败实际上来自ExpressionAPI:

var x = Expression.Parameter(typeof(byte));
var y = Expression.Parameter(typeof(byte));
var func = Expression.Lambda<Func<byte,byte,byte>>(
    Expression.Add(x,y), x, y).Compile(); // explodes here

修复它,MiscUtil 必须对byte/sbyte版本进行特殊处理;就像是:

var x = Expression.Parameter(typeof(byte));
var y = Expression.Parameter(typeof(byte));
var func = Expression.Lambda<Func<byte,byte,byte>>(
    Expression.Convert(
        Expression.Add(
            Expression.Convert(x, typeof(int)),
            Expression.Convert(y, typeof(int))
         ),typeof(byte)), x, y).Compile();

然而!我已经很久没有知道 Jon 的 repo 的密钥了;p

不过,奇怪的是,在原始 IL 中实现整个事情并不难......我实际上(在 USB 驱动器上)偶然发现了一个非常古老的 .NET 2.0(即之前Expression)版本的“通用运算符”我多年前写的那篇文章,也许可以胜任。或者更简单:只需在本地修补 MiscUtil 以处理byte/ sbyte

于 2013-01-16T13:12:12.437 回答
2

感谢 Marc 的回答,我修补了本地版本的 MiscUtil。使用ExpressionUtil.cs文件,我应用了以下补丁:

Index: ExpressionUtil.cs
===================================================================
--- ExpressionUtil.cs
+++ ExpressionUtil.cs
@@ -68,6 +68,18 @@
             {
                 try
                 {
+                    if (typeof(TArg1) == typeof(byte)
+                       || typeof(TArg1) == typeof(sbyte)
+                       || typeof(TArg2) == typeof(byte)
+                       || typeof(TArg2) == typeof(sbyte))
+                    {
+                        return Expression.Lambda<Func<TArg1, TArg2, TResult>>(
+                            Expression.Convert(body(
+                                    Expression.Convert(lhs, typeof(int)),
+                                    Expression.Convert(rhs, typeof(int))
+                                 ), typeof(TResult)), lhs, rhs).Compile();
+                    }
+
                     return Expression.Lambda<Func<TArg1, TArg2, TResult>>(body(lhs, rhs), lhs, rhs).Compile();
                 }
                 catch (InvalidOperationException)

所以也许有一天官方版本会更新,或者任何需要它的人都可以从这里获取并在本地应用补丁。

于 2013-01-16T14:13:22.877 回答