2010-11-17 28 views
11

Là một lập trình viên, tôi đã mong đợi điều này để ném một ngoại lệ. Có một lý do tại sao nó xử lý null là ""?C# thêm chuỗi + null không ném một lỗi?

string s = "hello"; 
string t = null; 

Console.WriteLine(s + t); 

Output:

chào

Chỉ cần nhấn mạnh câu hỏi của tôi, bạn có biết tại sao quyết định để biến rỗng vào String.Empty đã được thực hiện? Tôi đã mong đợi một số chuỗi được thêm vào nhưng đã có một vấn đề hơn nữa trở lại, nơi nó đã không được lấy nó đúng cách và nó trở lại với null. Vấn đề đã không được chú ý!

Dưới đây là một giả lý do tại sao tôi nghĩ rằng nó là xấu (và tại sao tôi đã bị sốc khi phát hiện ra không có lỗi):

Bạn có thể giả sử tôi quá tải ToString để cung cấp cho các tên của người hoặc các chi tiết về họ.

Person p = PersonDatabase.GetForName("Jimmy Gibbs"); 

Console.WriteLine("Name is: " + p.ToString()); 

Ném một ngoại lệ vì p là null

String p = PersonDatabase.GetForName("Jimmy Gibbs").Name; 

Console.WriteLine("Name is: " + p); 

Không ném một ngoại lệ, mặc dù p là null (nó đối xử với nó như là "").

(Nếu bạn muốn trở thành kén cá chọn canh và nói rằng tôi sẽ không thể để có được tên chính thức GetforName sẽ được null, nghĩ về nó như thế này :)

String p = PersonDatabase.GetNameFromID(1234); // Returns a string or null if not found 

Console.WriteLine("Name is: " + p); 

(Nếu bạn sử dụng giá trị này trong một danh sách hoặc mảng mà bạn sẽ kết thúc với một mục nhập trống, đó là những gì đã phá vỡ cho tôi, nó đã tạo javascript và cố gắng lấy phần tử theo ID "")

+2

WoW và + null viết hoa chữ cái đầu tiên là dấu cộng :) – Bolu

+0

Tôi chỉ có thể suy đoán là tại sao, nhưng một đối số có lợi sẽ giảm khả năng gây nhầm lẫn cho các nhà phát triển mới làm quen. trường hợp ngoại lệ là kết quả của dereferencing; có chúng gây ra bởi các nhà khai thác có thể không trực quan. Nó không phải là một lập luận rất tốt, theo ý kiến ​​của tôi, nhưng nó sẽ phù hợp với nguyên tắc ít ngạc nhiên nhất (nếu bạn không thêm gì vào cái gì đó, bạn vẫn mong đợi có cái gì đó). –

+0

Nếu bạn có thể sử dụng chuỗi t = null, bạn sẽ có thể sử dụng các toán tử khác với null. – Bolu

Trả lời

6

Toán tử + được phát ra là string.Concat trong kết quả IL.

s + t = string.Concat(s, t) 

và khi nhìn vào thực hiện nó kiểm tra xem đối số là null và trả string.Empty:

tháo rời với phản xạ:

[SecuritySafeCritical] 
public static string Concat(string str0, string str1) 
{ 
    if (IsNullOrEmpty(str0)) 
    { 
     if (IsNullOrEmpty(str1)) 
     { 
      return Empty; 
     } 
     return str1; 
    } 
    if (IsNullOrEmpty(str1)) 
    { 
     return str0; 
    } 
    int length = str0.Length; 
    string dest = FastAllocateString(length + str1.Length); 
    FillStringChecked(dest, 0, str0); 
    FillStringChecked(dest, length, str1); 
    return dest; 
} 
+1

Bạn có biết tại sao không? Chúng tôi đã có một lỗi khó chịu như là kết quả của điều này mà đã không được chú ý. – NibblyPig

+0

Đây là tài liệu: http://msdn.microsoft.com/en-us/library/a6d350wd.aspx (Một chuỗi rỗng được sử dụng thay cho bất kỳ đối số null nào.) –

18

Từ C# Language Specification:

7.8.4 Nhà điều hành bổ sung

Ghép nối chuỗi:

toán tử chuỗi + (chuỗi x, chuỗi y); toán tử chuỗi + (chuỗi x, đối tượng y); toán tử chuỗi + (đối tượng x, chuỗi y);

Quá tải của toán tử nhị phân + này thực hiện nối chuỗi. Nếu toán hạng của chuỗi nối là null, một chuỗi rỗng là được thay thế. Nếu không, bất kỳ đối số không chuỗi nào được chuyển đổi thành chuỗi đại diện bằng cách gọi phương thức ảo được thừa kế từ đối tượng loại . Nếu ToString trả về null, một chuỗi rỗng được thay thế.

+2

Tại sao đây là một ý tưởng hay? – NibblyPig

+2

@SLC Tôi tự hỏi nếu nó là để làm với thực tế là dây là loại tài liệu tham khảo nhưng cư xử như các loại giá trị trong rất nhiều cách (vì họ là bất biến). Vì vậy, có nó hành xử theo cách này (khi sử dụng toán tử +) phù hợp với khái niệm này. –

0

Các toán tử do người dùng xác định chỉ là các phương pháp tĩnh và tất nhiên có thể chấp nhận tham số null. Đây là ví dụ thực sự hữu ích cho các đại biểu.

Vì vậy, chuỗi chấp nhận null không phải là kỹ thuật mà là quyết định thiết kế. Và đôi khi có thể hữu ích khi xử lý null là "" vì rất nhiều mã người dùng xử lý chúng giống nhau.

0

Nếu tôi có cam và thêm một quả cam khác, bây giờ tôi có hai quả cam.

Nếu tôi có màu cam và thêm NOTHING, tôi vẫn có màu cam.

Để tôi thêm NULL vào chuỗi và nhận chuỗi gốc có vẻ hoàn toàn trực quan và ngữ nghĩa. NullReferenceExceptions nên được dành riêng khi truy cập các thuộc tính hoặc các phương thức cá thể trên các cá thể không tồn tại, ví dụ.

string myString = null; 
string lowerCaseString = myString.ToLower(); 

Sẽ dễ hiểu ném một NullReferenceException vì tôi đang cố gắng để truy cập ToLower() phương pháp dụ về một tham chiếu không tồn tại vì vậy Null Reference ngoại lệ (ví dụ. Có một điều trên Stack, nhưng không có gì trên Heap).

Có chuỗi hoạt động concat NULL ném ngoại lệ sẽ có nghĩa là tấn kiểm tra mã phòng thủ bổ sung NULL khi xử lý các chuỗi, điều này gây phiền nhiễu. Xin lỗi, nhưng tôi tình cờ đồng ý với cách C# .NET xử lý việc này. Java không làm như vậy?


Nếu bạn muốn kiểm tra xem một chuỗi chứa một giá trị sau đó sử dụng String.IsNullOrEmpty(myString); hoặc String.IsNullOrWhitespace(myString); (chỉ trong .NET 4.0)

-2

Trên thực tế đây là cách chuỗi được biểu diễn .... không có gì sai ở đó. null được sử dụng như một ký tự chấm dứt.

Ví dụ:

chuỗi a: "blahblah [null]" Vì vậy, bất cứ điều gì đọc chuỗi biết dừng lại ở null.

để sau đó khi bạn tạo chuỗi như sau: chuỗi b: "[null]" nó hoàn toàn hợp lệ.

Hiện tại, không có ký tự nào trước null. vì vậy khi chương trình của bạn bắt đầu đọc chuỗi nó gặp null (hoàn toàn hợp lệ) và dừng .... do đó ... chuỗi rỗng !!

+2

acctually cho C# này là về mặt kỹ thuật không chính xác tôi tin tưởng. Trong c, chúng được kết thúc bằng null, trong C# CLR giữ số lượng chuỗi mà chuỗi sử dụng và vị trí của nó. –

+2

Không chỉ không phải là cách C# lưu trữ chuỗi, nhưng toàn bộ lời giải thích ngay cả đối với C là khá không chính xác, gây nhầm lẫn biểu diễn của 'NULL' /' null' cho _ "con trỏ" _ bằng các ngôn ngữ như C/C++/C# ASCII ** nul ** _character_, ''\ 0''. – JonBrave

1

Khi suy nghĩ về quyết định thiết kế đã được thực hiện, chúng ta nên xem xét không chỉ ở nhà điều hành cộng cho chuỗi mà còn ở các lớp và phương pháp có liên quan, ví dụ: String.Concat(String, String)StringBuilder.Append(String). Các lớp đó là một phần của Base Class Library được sử dụng rộng rãi trong các ngôn ngữ khác (ví dụ: Visual Basic và F #).

Từ góc độ thiết kế ngôn ngữ và nền tảng, tất cả các phương pháp đó sẽ hoạt động trong một nhóm nhất quán (nghĩa là xử lý null theo cùng một cách). Tôi thấy ba tùy chọn có thể:

  • Ném ngoại lệ

    Đây là một "an toàn" giải pháp vì nó không rõ ràng phải làm gì với null. Như một sự cân bằng, nó sẽ đòi hỏi một phong cách phòng thủ hơn của lập trình và mã tiết hơn.

  • Sử dụng một số biểu diễn cho null, ví dụ: <null>, null hoặc [null] (kiểu Java)

    Đây là kết quả mà bạn mong đợi. Nó không phải là rõ ràng tại sao điều này sẽ xảy ra và làm thế nào chính xác null nên được đại diện.

  • Treat null trong thời trang tương tự như chuỗi rỗng (NET-style)

    Ý tưởng đằng sau nó là đại diện văn bản của null (ví dụ: một đối tượng mà là mất tích) là một chuỗi rỗng. Trong trường hợp đó, một lập trình viên có thể khai thác hành vi này và viết mã ngắn hơn. Mặt khác, nó có thể ẩn các lỗi.

Một số quyết định phải được thực hiện và tôi nghĩ rằng không có sự lựa chọn rõ ràng. Hành vi mong đợi trong C# và các ngôn ngữ .NET khác được ghi chép rõ ràng và nó nhất quán trên tất cả các phương thức xử lý ghép nối.

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