我正在使用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与byte
和sbyte
一起使用?
答案 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)
所以也许有一个闪亮的日子会更新正式版,或者任何需要它的人都可以从这里拿到它并在本地应用补丁。