将裸null文本与用户定义的运算符一起使用时的好奇重载决策

Jep*_*sen 5 c# null operator-overloading lifted-operators overload-resolution

(标题中的"用户定义"是指C#标准的加法和减法,TimeSpanDateTime不是C#标准的一部分.它们在BCL中定义.)

在可空TimeSpanDateTime值上玩弄提升的运算符,我写了下面的代码.请注意,这个框架提供了不同的操作TimeSpanDateTime.

有一个对称(和可交换)的加法,你接收两个TimeSpan并返回总和TimeSpan.这个加法的"逆"是减去两个,TimeSpan产生一个TimeSpan.

然后是另一种加法,非对称,你拿一个DateTime(左操作数)和一个TimeSpan(右操作数)来产生一个DateTime.由于此操作的不对称性,它有两种"反转"类型:一种是DateTime从中减去两种以获得TimeSpan差异,另一种是从中DateTime减去一种并从中减去一种TimeSpan以产生结果DateTime.

static void Main()
{
  DateTime? n_dt = new DateTime(2012, 12, 25);
  TimeSpan? n_ts = TimeSpan.FromDays(62.0);

  var a = n_dt + n_ts;   // OK
  var b = n_ts + n_ts;   // OK

  var c = null + n_dt;   // OK, string concatenation! Type of expression is String
  var d = null + n_ts;   // OK, compiler prefers TS+TS, not DT+TS
  var e = n_dt + null;   // OK, DT+TS
  var f = n_ts + null;   // OK, TS+TS
  var g = null + null;   // error, type of expression is undetermined

  var h = n_dt - n_dt;   // OK
  var i = n_dt - n_ts;   // OK
  var j = n_ts - n_ts;   // OK

  var k = null - n_dt;   // OK, DT-DT
  var l = null - n_ts;   // compiler prefers TS-TS, not DT-TS
  var m = n_dt - null;   // error, compiler won't choose between DT-DT amd DT-TS, type of expression is undetermined
  var n = n_ts - null;   // OK, TS-TS
  var o = null - null;   // OK, integer subtraction! Type of expression is Nullable<Int32>

  // illegal:
//var p = n_dt + n_dt;
//var q = n_ts + n_dt;
//var r = n_ts - n_dt;
}
Run Code Online (Sandbox Code Playgroud)

有些问题自然会出现.

这是有点奇怪的o是允许并给出int?(为什么不是一个long?顺便?)而g不允许.这是规格吗?此外,c通过字符串连接解决"不可能"这一点有点奇怪.显然,编译器决定nullin c是a (string)null.另一方面,object向a 添加显式类型的表达式DateTime将无法编译.

但我的主要问题是:为什么编译器可以为d和选择重载l,但是m它会抱怨模糊性?

Jep*_*sen 0

原因似乎是,对于m,两个可能的操作是在同一类型(即 )内定义的System.DateTime。他们之间没有办法选择。

另一方面,对于dl,一个运算在 中定义System.TimeSpan,另一个运算在 中定义System.DateTimed但是在and的行中l,我们看到了,但是在and的赋值中TimeSpan没有提到任何类型。编译器似乎只搜索 type 中定义的运算符,而忘记搜索所有其他类型中定义的用户定义运算符(顺便说一下,要搜索的类型非常多)。这样,在解析and期间,编译器永远不会发现类型内部定义的运算符。DateTimedlSystem.TimeSpandlDateTime