Question

(The "user-defined" in the title refers to the fact that addition and subtraction of TimeSpan and DateTime are not a part of the C# standard. They are defined in the BCL.)

Playing around with lifted operators on nullable TimeSpan and DateTime values, I wrote the following code. Note that the framework offers different operations on TimeSpan and DateTime.

There's one symmetrical (and commutative) addition where you take in two TimeSpan and return the sum TimeSpan. The "inverse" of this addition is the subtraction of two TimeSpan yielding a TimeSpan.

Then there's another kind of addition, asymmetrical, where you take one DateTime (left operand) and one TimeSpan (right operand) to produce a DateTime. Because of the asymmetry of this operation, it has two "kinds" of inverses: One where you subtract two DateTime from each other to get the TimeSpan difference, and one where you have one DateTime and subtract from it one TimeSpan to produce a result 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;
}

Some questions arise naturally.

It's a bit strange that o is allowed and gives an int? (why not a long? by the way?) while g is disallowed. Is this in the spec? Also, it's a little strange that the "impossible" c is resolved by string concatenation. Apparently the compiler decides that the null in c is a (string)null. Adding an expression of explicit type object to a DateTime, on the other hand, will not compile.

But my main question is: Why can the compiler choose an overload for d and l, but with m it complains about ambiguity?

Was it helpful?

Solution

The reason seems to be that with m, the two possible operations are defined inside the same type, namely System.DateTime. There's no way to choose between them.

On the other hand, with d and l, one operation is defined in System.TimeSpan, and the other one is defined in System.DateTime. But in the lines of d and l, we see TimeSpan, but there's no mention of any DateTime type what so ever in the assignments of d and l. It seems like the compiler then only searches through operators defined in the type System.TimeSpan, and forgets to search through user-defined operators defined in all other types (which would by the way be very many types to search). In that way, during the resolution of d and l, the compiler never discovers the operators defined inside the DateTime type.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top