2012-04-16 19 views
6

thể trùng lặp:
Why check this != null?Tại sao String.Equals (Object obj) kiểm tra xem nếu điều này == null?

// Determines whether two strings match. 
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] 
public override bool Equals(Object obj) 
{ 
    //this is necessary to guard against reverse-pinvokes and 
    //other callers who do not use the callvirt instruction 
    if (this == null) 
     throw new NullReferenceException(); 

    String str = obj as String; 
    if (str == null) 
     return false; 

    if (Object.ReferenceEquals(this, obj)) 
     return true; 

    return EqualsHelper(this, str); 
} 

Phần Tôi không hiểu là một thực tế rằng nó được kiểm tra các trường hợp hiện tại, this, chống lại null. Nhận xét có chút khó hiểu, vì vậy tôi đã tự hỏi ý kiến ​​đó thực sự có ý nghĩa gì?

Bất cứ ai có thể đưa ra một ví dụ về việc làm thế nào điều này có thể phá vỡ nếu kiểm tra đó không có, và điều này có nghĩa là tôi cũng nên đặt kiểm tra trong các lớp học của tôi?

+0

@FlorianGreinacher: Không phải là bản sao có thể, nhưng khá nhiều bản sao chính xác, lol. Tôi tự hỏi tại sao nó không xuất hiện trong "Liên quan" khi tôi viết câu hỏi của tôi? –

Trả lời

6

Kiểm tra đó có sẵn để bảo vệ chống lại mã gốc có thể gọi hàm bằng con trỏ rỗng this. Điều này không thể xảy ra trong C#, vì vậy bạn không cần phải đặt các vệ sĩ tương tự trong mã của bạn. Có thể là lớp String được viết trước khi C# được hoàn thành và tác giả có thể nghĩ rằng nó quan trọng để bảo vệ chống lại null, hoặc có thể nó chỉ phổ biến để gọi String các phương thức từ mã gốc và những nơi khác. .

Lưu ý rằng ngay cả khi bạn quản lý để có được gọi với một null this và bạn không có bảo vệ, tất cả những gì sẽ xảy ra là ngoại lệ sẽ hơi khác nhau. Nó có thể là một ngoại lệ khác và nó có thể bị ném bởi một thành viên khác, nhưng nếu không nó sẽ không tạo ra sự khác biệt.

Nói cách khác, nếu kiểm tra rỗng không có ở đó, EqualsHelper (hoặc một trong các callees của nó) sẽ ném ngoại lệ thay vì Equals. Vì nó là mong muốn để ẩn các bên trong của chức năng người dùng có thể nhìn thấy, nó làm cho tinh thần để đặt kiểm tra ngay lúc đầu.

2
  • Các ngôn ngữ như C# và VB.NET sử dụng callvirt để ném NullReference trước khi kiểm tra phương pháp thể hiện (this == null) là không cần thiết.
  • Các ngôn ngữ như F # và Managed C++ (phần lớn thời gian) sử dụng lệnh gọi nơi bạn có thể truy cập vào một phương thức thể hiện bằng một con trỏ rỗng này. (this == null) không có hiệu lực.

Kiểm tra null bổ sung không chỉ dành cho ngôn ngữ thứ hai mà còn hỗ trợ khả năng gỡ lỗi ở vị trí mà lỗi (gọi phương thức thể hiện của đối tượng rỗng). Nếu không có ở đó, bạn có thể gọi bất kỳ phương thức nào trong lớp mà không có bất kỳ lỗi nào miễn là điều này không bao giờ là các tham số (truy cập các biến thành viên). Điều này có thể đi xa đến mức đối tượng null của bạn một số cuộc gọi phương thức đã làm việc và đột nhiên bạn nhận được một ngoại lệ tham chiếu null (phương thức mà dữ liệu cá thể được truy cập).

Nếu bạn nhìn vào các kiểm tra bên trong các lớp .NET rõ ràng là chỉ trên một số lớp nổi bật như chuỗi có chứa các vệ sĩ như vậy. Các phương thức khác như IndexOf không bảo vệ chống lại điều này. Điều này là không phù hợp nhưng tôi nghĩ rằng hình phạt hiệu suất cho kiểm tra null đôi như vậy không đáng để nỗ lực vì hầu hết người dùng BCL là ngôn ngữ sử dụng lệnh callvirt trong đó kiểm tra null thứ hai không giúp ích gì.

+1

Trong F #, 'let x =" a ".Bằng ("b") 'vẫn biên dịch thành' callvirt' – colinfang