如何在System.Byte上使用MiscUtil.Operator?

时间:2013-01-16 13:00:10

标签: c# generics

我正在使用MiscUtil运算符一段时间没有任何大问题。但现在我发现了一些让我烦恼的事情:

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#中,这些类型将被隐式转换为Int32,并确实实现了这些运算符。

现在的问题是:有没有机会让MiscUtil与bytesbyte一起使用?

2 个答案:

答案 0 :(得分:5)

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

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的回购钥匙以来已经很久了; p

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

答案 1 :(得分: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)

所以也许有一个闪亮的日子会更新正式版,或者任何需要它的人都可以从这里拿到它并在本地应用补丁。