2013-07-09 32 views
5
DateTime? date = null; 
string tmp = "a" + "(" + date ?? "blablabla" + ")"; 

Console.WriteLine(tmp); 

Điều này sẽ in nội dung nào đó gần: 'a ('.Đây có phải là lỗi trong trình biên dịch Visual Studio 2010 không?

Đây có phải là lỗi với null-coalescing operator không? Nếu tôi đặt date ?? "blablabla" trong dấu ngoặc đơn, nó được gạch dưới là lỗi.

+3

Đừng bao quanh 'ngày ?? "blablabla" 'với niềng răng, nhưng với dấu ngoặc đơn, và cho chúng tôi biết nếu điều đó thay đổi một cái gì đó. –

+14

"đây có phải là lỗi trình biên dịch không?" 99,99% thời gian câu trả lời là ** không **. –

+0

Tôi chỉ từng tìm thấy một lỗi trình biên dịch duy nhất, và đó là 20 năm trước. Và đó là một điều dễ dàng để xác nhận trong đó một cuộc gọi được biên dịch thành mã hỏng hóc trong một phiên bản của trình biên dịch cụ thể đó nhưng vẫn hoạt động khác nhau (và chính xác) trong cả hai phiên bản trước và sau. Đây không phải là một trường hợp như thế. – jwenting

Trả lời

5

Trước tiên, bạn nên always assume it's your fault, không phải lỗi của trình biên dịch; select isn't broken. Bạn có thực sự nghĩ rằng việc thực hiện Visual Studio 2010 của nhà điều hành ?? chưa được thử nghiệm? Khi bạn gặp phải điều gì đó không phù hợp với kỳ vọng của bạn, hãy kiểm tra kỳ vọng của bạn. Nhận hướng dẫn và đảm bảo rằng bạn hiểu chính xác điều gì sẽ xảy ra. Trong trường hợp này, hãy mở đặc tả ngôn ngữ.

Nếu bạn tiến hành §1.4 trong số specification, bạn sẽ thấy một bảng phân nhóm các toán tử thành các nhóm ưu tiên; bạn cũng có thể tìm thấy nó online. Cụ thể, toán tử hợp nhất null ?? nằm gần dưới cùng, phía trên chỉ có toán tử và phép gán ternary có điều kiện thấp và =>. Đó là bên dưới toán tử cộng. Như vậy, tuyên bố của bạn

string tmp = "a" + "(" + date ?? "blablabla" + ")"; 

được xử lý bởi trình biên dịch như

string tmp = (("a" + "(" + date) ?? ("blablabla" + ")")); 

Tôi sẽ không được hoàn toàn pedantic và cũng nghĩ giải lao biểu thức phụ gia đầu tiên . Kể từ khi rời khỏi tay-side của biểu thức trong tuyên bố đó là không bao giờ null, tất nhiên nó luôn gán "a(" (hoặc "a(" + date.ToString() khi date.HasValue là đúng) để tmp.

Các chính điểm là bạn có một kỳ vọng không chính xác như những gì nên xảy ra rằng bạn nên đã xác minh chống lại bằng tay.

Nếu tôi đặt date ?? "blablabla" trong ngoặc đơn, nó được gạch dưới là lỗi.

Tất nhiên rồi. Bạn thậm chí đã đọc thông báo lỗi chưa? Nó có thể cho bạn biết rằng bạn không thể làm ?? trên số DateTime?string vì không có chuyển đổi tiềm ẩn giữa DateTime?string theo một trong hai hướng. Điều này cũng được đề cập trong đặc tả ngôn ngữ; xem §7.13.Bạn phải đọc tin nhắn này và trả lời cho nó. Để có được một cái gì đó ngữ nghĩa tương đương với những gì bạn đang cố gắng để thể hiện, bạn sẽ phải nghỉ mát để các nhà điều hành ternary có điều kiện:

date.HasValue ? date.ToString() : "blablabla" 

và sau đó quấn rằng toàn bộ sự việc trong ngoặc vì các nhà điều hành ternary có điều kiện có rất ưu tiên thấp.

Cuối cùng, tôi tìm thấy phiên bản mã hóa chính xác của mã của bạn thay vì xấu xí, không vui để đọc và có thể không thú vị để duy trì. Chỉ cần làm cho nó đơn giản, đề nghị:

var tmp = String.Format("a({0})", 
         date.HasValue ? date.ToString() : "blablabla"); 

Bây giờ nó là nên rõ ràng những gì đang xảy ra và những gì sẽ xảy ra. Tôi không phải nghĩ rằng để hiểu điều đó. Lưu suy nghĩ của bạn cho những vấn đề khó khăn bạn sẽ gặp phải.

: Hãy cẩn thận. Chúng tôi sẽ cần phải thêm vào một cuộc gọi phương thức để date.ToString (trong đó có ưu tiên cao nhất) trước khi cố gắng tìm ra chính xác những gì được đánh giá trước tiên.

+2

Câu trả lời này tốt hơn nhiều so với câu trả lời được chọn. –

0

Điều này rất có thể là do date không phải là chuỗi và nhà điều hành ?? không thể xác định loại cơ sở chung cho date"blablabla". Hãy thử (date.ToString() ?? "blablabla"). Nhưng điều này sẽ không thỏa mãn nhu cầu của bạn hoặc vì date.ToString() sẽ không bao giờ là null.

string tmp = "a" + "(" + (date ?? DateTime.Now) + ")"; 

sẽ hoạt động.

+0

Plus, nếu 'date' là' null', và bạn cố gắng gọi 'ToString()' trên nó, bạn sẽ nhận được 'NullReferenceException' (Hmm, điều đó chỉ đúng với các kiểu nullable là các kiểu tham chiếu-- và 'DateTime' là một ValueType, do đó, nullable cho nó sẽ là giá trị kiểu' Nullable 'thay vì lớp dựa trên một - vì vậy có lẽ điều này sẽ là ok?). – fourpastmidnight

+0

@fourpastmidnight Đề xuất của bạn là chính xác - ((DateTime?) Null). ToString() thực hiện mà không có lỗi. – Artemix

+0

Thật tuyệt, cảm ơn vì điều đó. – fourpastmidnight

2

"blablabla" không phải là ngày, vì vậy bạn không thể sử dụng là đặt date?.


string tmp = "a" + "(" + date ?? "blablabla" + ")"; 

tương đương với

string tmp = ("a" + "(" + date) ?? ("blablabla" + ")"); 

đó là nơi a( của bạn đến từ.


Tuy nhiên

string tmp = "a" + "(" + (date ?? DateTime.Now) + ")"; 

hoặc tương tự nên làm việc.

0

Nó không phải là lỗi với toán tử kết hợp null.

Đó là operator precedence:

"a" + "(" + date ?? "blablabla" + ")" 

là giống như:

("a" + "(" + date.ToString()) ?? ("blablabla" + ")") 

("a" + "(" + date.ToString()) không phải là null.

8

Null-coalescing operator?? có độ ưu tiên thấp hơn so với các nhà điều hành +, do đó, mã của bạn bằng

string tmp = ("a" + "(" + date) ?? ("blablabla" + ")"); 

Kể từ khi tất cả mọi thứ trong hoạt động + với một chuỗi tạo ra một chuỗi (bằng cách gọi .ToString() trên tất cả các toán hạng không theo chuỗi), mã của bạn sẽ luôn sản xuất chuỗi "a(".

+0

"ưu tiên" hơn "ưu tiên", tôi muốn nói. –

+0

Điều quan trọng cần lưu ý là một chuỗi không null được kết hợp với các kết quả null trong chuỗi không null, chứ không phải là một lỗi hoặc null, do đó, '+ date' thực sự là một no-op. – Servy

1

Từ C# Language Specification §1.4

Bảng dưới đây tóm tắt các nhà khai thác C#’s, liệt kê các nhà điều hành loại theo thứ tự ưu tiên từ cao nhất đến thấp nhất. Các toán tử trong cùng danh mục có quyền ưu tiên bằng nhau.

Nó cho biết Additive operators là ưu tiên cao hơn so với toán tử kết hợp rỗng.

Vì vậy, + có mức độ ưu tiên cao hơn ?? và đó là lý do tại sao biểu thức "blablabla" + ")" hoạt động trước tiên.

Và kể từ datenull, tuyên bố hoạt động như;

string tmp = "a" + "(" + null; 

Và thường dẫn sẽ a(

3

Dưới đây chỉ là một phiên bản khác:

DateTime? date = null; 
string tmp = string.Format("a({0})", 
          date.HasValue ? date.ToString() : "blablabla"); 

Tôi thực sự yêu string.Format thay vì nối.

+1

Tôi cũng vậy; Tôi cho tất cả, nhưng các biểu thức đơn giản nhất dẫn đến mã dễ đọc hơn và dễ bảo trì hơn. – jason

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