5

("do người dùng xác định" trong tiêu đề đề cập đến việc cộng và trừ TimeSpanDateTime không phải là một phần của tiêu chuẩn C#. được xác định trong BCL.)Độ phân giải quá tải nghiêm trọng khi sử dụng chữ cái rỗng không xác định với toán tử do người dùng xác định

Chơi xung quanh với toán tử được dỡ bỏ trên giá trị TimeSpanDateTime không có giá trị, tôi đã viết mã sau đây. Lưu ý rằng khung công tác cung cấp các hoạt động khác nhau trên TimeSpanDateTime.

Có một phép cộng đối xứng (và giao hoán) mà bạn nhận được trong hai số TimeSpan và trả lại số tiền TimeSpan. "Nghịch đảo" của phần bổ sung này là phép trừ của hai số TimeSpan cho một số TimeSpan.

Sau đó, có một loại bổ sung, không đối xứng, nơi bạn lấy một DateTime (toán hạng bên trái) và một TimeSpan (toán hạng bên phải) để tạo ra một DateTime. Do tính bất đối xứng của thao tác này, nó có hai "loại" của các nghịch đảo: Một trong đó bạn trừ hai số DateTime khỏi nhau để có chênh lệch TimeSpan và một nơi bạn có một số DateTime và trừ nó TimeSpan để tạo ra kết quả 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; 
} 

Một số câu hỏi phát sinh một cách tự nhiên.

Có một chút lạ là o được phép và cung cấp cho int? (tại sao không phải là long? bằng cách này?) Trong khi g không được phép. Đây có phải là thông số kỹ thuật không? Ngoài ra, có một chút lạ là "không thể" c được giải quyết bằng cách nối chuỗi. Rõ ràng trình biên dịch quyết định rằng null trong c(string)null. Việc thêm một biểu thức loại rõ ràng object vào một DateTime, mặt khác, sẽ không biên dịch.

Nhưng câu hỏi chính của tôi là: Tại sao trình biên dịch có thể chọn một tình trạng quá tải cho dl, nhưng với m nó than phiền về sự mơ hồ?

+3

Cho đến nay điều kỳ lạ nhất ở đây là var o = null - null; –

+0

'c' sử dụng nối chuỗi vì các toán tử ngôn ngữ được ưu tiên hơn các toán tử do người dùng định nghĩa, và biểu thức đó khớp với toán tử nối chuỗi của toán tử' + (chuỗi, đối tượng) '. Điều đó tất nhiên đặt ra câu hỏi của 'd' mặc dù, như logic đó cũng nên giải quyết để nối chuỗi. – Servy

+0

@DaveBish Đồng ý. Tôi cho rằng nó sẽ là mơ hồ giữa int/long – Servy

Trả lời

0

Lý do có vẻ là rằng với m, hai hoạt động có thể là định nghĩa bên cùng loại, cụ thể là System.DateTime. Không có cách nào để lựa chọn giữa chúng.

Mặt khác, với dl, một hoạt động được xác định trong System.TimeSpan và một hoạt động khác được xác định trong System.DateTime. Nhưng trong các dòng của dl, chúng tôi thấy TimeSpan, nhưng không có đề cập đến bất kỳ bất kỳ DateTime nhập nội dung nào vào các nhiệm vụ dl. Dường như trình biên dịch chỉ tìm kiếm thông qua các toán tử được định nghĩa trong loại System.TimeSpan và quên tìm kiếm thông qua các toán tử do người dùng xác định trong tất cả các loại khác (theo cách này có rất nhiều loại để tìm kiếm). Theo cách đó, trong độ phân giải dl, trình biên dịch không bao giờ phát hiện ra các toán tử được xác định bên trong loại DateTime.

+1

Xem phần 7.3.4 của thông số C#, vì nó dường như có liên quan và để xác nhận câu trả lời này. – Servy

+0

"Nhân tiện". – phoog

Các vấn đề liên quan