Dấu chấm hỏi và toán tử dấu chấm là gì? có nghĩa là trong C # 6.0?


359

Với C # 6.0 trong bản xem trước VS2015, chúng tôi có một toán tử mới ?., có thể được sử dụng như thế này:

public class A {
   string PropertyOfA { get; set; }
}

...

var a = new A();
var foo = "bar";
if(a?.PropertyOfA != foo) {
   //somecode
}

Chính xác thì nó làm gì?

Câu trả lời:


500

Đó là toán tử điều kiện null . Về cơ bản nó có nghĩa là:

"Đánh giá toán hạng thứ nhất; nếu đó là null, hãy dừng lại, với kết quả là null. Nếu không, hãy đánh giá toán hạng thứ hai (với tư cách là thành viên của toán hạng thứ nhất)."

Trong ví dụ của bạn, vấn đề là nếu anull, sau đó a?.PropertyOfAsẽ đánh giá để nullthay vì ném một ngoại lệ - sau đó nó sẽ so sánh rằng nulltài liệu tham khảo với foo(sử dụng chuỗi của ==quá tải), tìm họ không bình đẳng và thực hiện sẽ đi vào cơ thể của iftuyên bố .

Nói cách khác, nó như thế này:

string bar = (a == null ? null : a.PropertyOfA);
if (bar != foo)
{
    ...
}

... ngoại trừ việc đó achỉ được đánh giá một lần.

Lưu ý rằng điều này cũng có thể thay đổi loại biểu thức. Ví dụ, xem xét FileInfo.Length. Đó là một thuộc tính của loại long, nhưng nếu bạn sử dụng nó với toán tử điều kiện null, thì bạn kết thúc bằng một biểu thức của loại long?:

FileInfo fi = ...; // fi could be null
long? length = fi?.Length; // If fi is null, length will be null

8
Nó không được gọi là toán tử điều kiện null ?
SLaks 5/2/2015

1
@SLaks: Tôi nghĩ đó là "null có điều kiện" nhưng tôi có thể sai. Lần trước tôi đã kiểm tra các tài liệu về ngôn ngữ Roslyn, nó cũng không được đổi tên thành. Có thể nguồn là cơ quan có thẩm quyền ở đây - sẽ kiểm tra.
Jon Skeet

3
@SLaks: Chắc chắn rồi. Trong SyntaxKind, rõ ràng là Cond điều hànhAccessExpression, điều gây khó chịu cho cả hai ...
Jon Skeet

12
tôi thích cái tên "Elvis" toán tử: P
Ahmed ilyas 5/2/2015

3
Chỉ để ghi lại tôi đã thấy năm tên khác nhau cho toán tử này: điều hướng an toàn, điều kiện null, lan truyền null, truy cập có điều kiện, Elvis.
Gigi

81

Nó có thể rất hữu ích khi làm phẳng một đối tượng phân cấp và / hoặc ánh xạ. Thay vì:

if (Model.Model2 == null
  || Model.Model2.Model3 == null
  || Model.Model2.Model3.Model4 == null
  || Model.Model2.Model3.Model4.Name == null)
{
  mapped.Name = "N/A"
}
else
{
  mapped.Name = Model.Model2.Model3.Model4.Name;
}

Nó có thể được viết như thế (logic tương tự như trên)

mapped.Name = Model.Model2?.Model3?.Model4?.Name ?? "N/A";

Ví dụ làm việc DotNetFiddle.Net .

( toán tử kết hợp ?? hoặc null khác với toán tử có điều kiện? hoặc null ).

Nó cũng có thể được sử dụng ngoài các toán tử gán với Action. Thay vì

Action<TValue> myAction = null;

if (myAction != null)
{
  myAction(TValue);
}

Nó có thể được đơn giản hóa để:

myAction?.Invoke(TValue);

Ví dụ về DotNetFiddle :

sử dụng hệ thống;

public class Program
{
  public static void Main()
  {
    Action<string> consoleWrite = null;

    consoleWrite?.Invoke("Test 1");

    consoleWrite = (s) => Console.WriteLine(s);

    consoleWrite?.Invoke("Test 2");
  }
}

Kết quả:

Kiểm tra 2


27
Để cứu người đang tìm kiếm những gì ?? là .. Nó là toán tử hợp nhất null và sẽ trả về Tên nếu nó không phải là null, nếu không nó sẽ trả về "N / A".
Steve

6
@Erik Philips Tôi nghĩ bạn cần thêm || Model.Model2.Model3.Model4.Name == null để có cùng logic, nếu không, trong trường hợp Model.Model2.Model3.Model4.Namenull, mapped.Namesẽ ở lạinull
RazvanR

2
@ErikPhilips Không phải trên cùng một trang tôi đoán. Hãy thử xem những gì xảy ra trong cả hai trường hợp của bạn nếu Model.Model2.Model3.Model4.Namenull.
RazvanR

1
Kết quả là "Không có", một lần nữa VUI LÒNG ĐỌC NHẬN XÉT ĐẦU TIÊN. Ví dụ làm việc DotNetFiddle.Net .
Erik Philips

7
@ErikPhilips: Điều đó không liên quan gì đến bình luận đầu tiên, vì điều này không liên quan đến ví dụ đầu tiên của bạn. Trong trường hợp này, bạn sẽ nhảy vào else-branch và có mapped.Name = Model.Model2.Model3.Model4.Name -> mapped.Name = null, trong khi ví dụ thứ hai của bạn sẽ thay thế mapped.Name = "N/A". Xem DotNetFiddle đã chỉnh sửa
derM

3

Điều này tương đối mới đối với C # giúp chúng ta dễ dàng gọi các hàm liên quan đến các giá trị null hoặc không null trong chuỗi phương thức.

cách cũ để đạt được điều tương tự là:

var functionCaller = this.member;
if (functionCaller!= null)
    functionCaller.someFunction(var someParam);

và bây giờ nó đã được thực hiện dễ dàng hơn nhiều chỉ với:

member?.someFunction(var someParam);

Tôi thực sự khuyên bạn nên đọc nó ở đây:

https://docs.microsoft.com/en-us/dotnet/csharp/lingu-reference/operators/null-conditable-operators

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.