2010-11-05 26 views
6

thể trùng lặp:
Shortcut for “null if object is null, or object.member if object is not null”Toán tử điều hướng an toàn trong C#?

Một số ngôn ngữ có một nhà điều hành chuyển hướng an toàn cho phép bạn không phải lo lắng về trường hợp ngoại lệ tham khảo null.

Ví dụ về ngôn ngữ Groovy:

String lname = person.Name.ToLowerCase(); //throws exception if Name is null 
String lname = person.Name?.ToLowerCase();//lname will be null if Name was null 

Làm thế nào tôi có thể thực hiện một cái gì đó tương tự như sau trong C#? Giải pháp của tôi cho đến nay là một phương pháp mở rộng như sau:

public static T o<T>(this T obj) where T : new() 
{ 
      return obj != null ? obj : new T(); 
} 
//used like: String lname = person.o().Name; //returns null if person was null 

Tuy nhiên, điều này chỉ hoạt động trong một số trường hợp.

+0

http://visualstudio.uservoice.com/forums/121579-visual-studio/suggestion/3990187-add-operator-to-c-? Tracking_code = 594c10a522f8e9bc987ee4a5e2c0b38d – Hawxby

+0

Tại thời điểm viết bài này, tính năng này thực sự được lên kế hoạch cho C# 6: xem [.NET Compiler Platform ("Roslyn")): Trạng thái tính năng ngôn ngữ: Toán tử lan truyền Null '? .'] (http://roslyn.codeplex.com/discussions/540883) – stakx

Trả lời

9

Đối với những trường hợp này tôi có xu hướng sử dụng một phương pháp mở rộng gọi là IfNotNull:

public static OUT IfNotNull<IN, OUT>(this IN v, Func<IN, OUT> f) 
    where IN : class where OUT : class 
{ 
    return v == null ? null : f(v); 
} 

Tinh vi hơn là giới thiệu khái niệm về Có thể. Một ví dụ được đưa ra bởi derick bailey here.

Cập nhật:

Tính đến C# 6 có bây giờ là một nhà điều hành null-tuyên truyền mà cú pháp khôn ngoan trông giống hệt như một Groovy.

+1

Điều này có vẻ như một giải pháp khá tốt. Cho phép bạn không phá vỡ phương pháp chuỗi và không phải giới thiệu một biến tạm thời, đó là những lý do chính tôi muốn sử dụng một toán tử điều hướng an toàn. – Kyle

+1

Điều này phụ thuộc vào 'OUT' là một loại nullable. Bạn có thể mở rộng này cho tất cả các kiểu bằng cách: 1. remove 'where OUT: class', 2. thay đổi phần thân thành' return v == null? mặc định (OUT): f (v); '. –

+0

Làm thế nào để v lấy được từ o? Đó là toàn bộ vấn đề, để có thể làm sth với o nếu nó không phải là null. – flq

3

Tôi không biết về việc trả lại một null từ cái gì đó là đảm bảo để không được null, nhưng để bảo đảm một tham chiếu đối tượng, bạn có thể sử dụng cái gì đó Null Coalescing Operator??

như:

string lname = (person.Name??String.Empty).ToLower(); 

Nó sẽ trả về một chuỗi rỗng thay vì null cho trường hợp rỗng, nhưng nó sẽ hoạt động.

Trả về một chuỗi trống có ý nghĩa hơn là trả về giá trị rỗng; nếu bạn trả về một null, nó sẽ ném lại nếu bạn nối một toán tử khác vào nó.

+0

Bạn có thể viết phương thức mở rộng' ToLowerCase', nhưng tôi có thể chỉ sử dụng trong phương thức 'ToLower' trên đối tượng chuỗi. –

+0

+1 để sử dụng toán tử '??'. – ThiefMaster

+1

?? là toán tử C# yêu thích của tôi. – Bryan

2

Không tồn tại trong C# hôm nay, nhưng bạn có thể viết nó bằng SelectMany.

String lname = from _ in person.Name from s in _.ToUpper() select s; 

hoặc

String lname = person.Name.SelectMany(_ => _.ToUpper(), s => s); 

(Đó là đề nghị Bart De Smet trong his PDC 2010 talk on the future of LINQ Xem trượt # 6..)

+0

Khá mờ .. –

+1

Lưu ý rằng 'SelectMany' trong trường hợp này không phải là LINQ' SelectMany' thông thường nhưng một 'SelectMany' tùy chỉnh được tạo để triển khai thực đơn' Maybe'. –

4

Bạn đang tìm kiếm ngắn mạch null-conditional member access operator ?. đã được giới thiệu trong ngôn ngữ C# phiên bản 6 (được triển khai trong Visual Studio 2015).

Phần còn lại của câu trả lời của tôi được viết cho các phiên bản trước của ngôn ngữ C# mà không có nhà điều hành ?..


Nói chung, nếu bạn đang ở trong một tình huống mà bạn đang truy cập một sâu sắc "lồng" bất động sản, chẳng hạn như outermostObject.a.b.c.X, có lẽ bạn nên xem xét lại thiết kế mã của bạn, như là một sự tiếp cận đó có thể chỉ ra rằng bạn đang vi phạm các nguyên tắc OO đã được thiết lập (chẳng hạn như nguyên tắc ít kiến ​​thức nhất, còn gọi là Luật Demeter).

Một số tùy chọn khác:

Đầu tiên, một chất chống gợi ý — không làm điều này:

string lname = null; 
try 
{ 
    lname = Person.Name.ToLower(); 
} 
catch (NullReferenceException ex) { } // inefficient and ugly 

Second, sử dụng một cái gì đó giống như một Maybe đơn nguyên — bạn có thể định nghĩa như một nhập chính bạn. Về cơ bản nó là một Nullable<T> thực hiện IEnumerable<T> sao cho nó trả về một chuỗi rỗng khi không có giá trị nào được đặt hoặc một chuỗi chính xác một phần tử nếu giá trị được đặt. sau đó bạn muốn sử dụng nó như sau:

Maybe<string> personName = person.Name; 
var lname = (from name in personName select name.ToLower()).FirstOrDefault(); 

Thứ ba, và có lẽ là giải pháp dễ nhất và thiết thực nhất, theo đề nghị của ulrichb:

var lname = person.Name != null ? person.Name.ToLower() : null; 

T.B., vì chúng tôi đã về chủ đề kiểm tra cho null, đừng quên kiểm tra xem personnull trước khi truy cập tài sản Name của nó ... ;-)

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