Chạy qua dòng mã này:
FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();
Hai dấu hỏi có ý nghĩa gì, nó có phải là một loại toán tử ternary không? Thật khó để tìm kiếm trong Google.
Chạy qua dòng mã này:
FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();
Hai dấu hỏi có ý nghĩa gì, nó có phải là một loại toán tử ternary không? Thật khó để tìm kiếm trong Google.
Câu trả lời:
Đó là toán tử hợp nhất null và khá giống toán tử ternary (ngay lập tức nếu). Xem thêm ?? Toán tử - MSDN .
FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();
mở rộng tới:
FormsAuth = formsAuth != null ? formsAuth : new FormsAuthenticationWrapper();
mà mở rộng hơn nữa để:
if(formsAuth != null)
FormsAuth = formsAuth;
else
FormsAuth = new FormsAuthenticationWrapper();
Trong tiếng Anh, nó có nghĩa là "Nếu bất cứ thứ gì ở bên trái không phải là null, hãy sử dụng cái đó, nếu không thì sử dụng cái gì ở bên phải."
Lưu ý rằng bạn có thể sử dụng bất kỳ số nào trong số này theo thứ tự. Câu lệnh sau sẽ gán giá trị không null đầu tiên Answer#
cho Answer
(nếu tất cả các Câu trả lời là null thì Answer
là null):
string Answer = Answer1 ?? Answer2 ?? Answer3 ?? Answer4;
Ngoài ra, điều đáng nói trong khi việc mở rộng ở trên là tương đương về mặt khái niệm, kết quả của mỗi biểu thức chỉ được đánh giá một lần. Điều này rất quan trọng nếu ví dụ một biểu thức là một cuộc gọi phương thức với các tác dụng phụ. (Tín dụng cho @Joey vì đã chỉ ra điều này.)
??
là liên kết trái, vì vậy a ?? b ?? c ?? d
tương đương với ((a ?? b) ?? c ) ?? d
. "Các toán tử gán và toán tử ternary (? :) là liên kết phải. Tất cả các toán tử nhị phân khác là liên kết trái." Nguồn: msdn.microsoft.com/en-us/l Library / ms173145.aspx
Chỉ vì chưa có ai nói những lời kỳ diệu: đó là toán tử kết hợp null . Nó được định nghĩa trong phần 7.12 của đặc tả ngôn ngữ C # 3.0 .
Nó rất tiện dụng, đặc biệt là do cách nó hoạt động khi nó được sử dụng nhiều lần trong một biểu thức. Một biểu thức của mẫu:
a ?? b ?? c ?? d
sẽ đưa ra kết quả của biểu thức a
nếu nó không null, nếu không thì thử b
, nếu không thì thử c
, nếu không thì thử d
. Nó ngắn mạch ở mọi điểm.
Ngoài ra, nếu loại d
không phải là nullable, loại của toàn bộ biểu thức cũng không phải là nullable.
Đó là toán tử hợp nhất null.
http://msdn.microsoft.com/en-us/l Library / ms173224.aspx
Có, gần như không thể tìm kiếm trừ khi bạn biết nó được gọi là gì! :-)
EDIT: Và đây là một tính năng thú vị từ một câu hỏi khác. Bạn có thể xâu chuỗi chúng.
Cảm ơn mọi người, đây là lời giải thích ngắn gọn nhất mà tôi tìm thấy trên trang MSDN:
// y = x, unless x is null, in which case y = -1.
int y = x ?? -1;
-1
chỉ là một đơn giản int
, không thể rỗng).
x
là loại int?
, nhưng y
là loại int
, bạn có thể viết int y = (int)(x ?? -1)
. Nó sẽ phân tích x
thành một int
nếu nó không null
, hoặc gán -1
cho y
nếu x
có null
.
Hai dấu hỏi (??) chỉ ra rằng nó là toán tử Coalescing.
Toán tử hợp nhất trả về giá trị NON-NULL đầu tiên từ một chuỗi. Bạn có thể xem video youtube này thể hiện toàn bộ thực tế.
Nhưng hãy để tôi thêm nhiều hơn những gì video nói.
Nếu bạn thấy ý nghĩa tiếng Anh của việc kết hợp lại, nó nói rằng hợp nhất với nhau. Ví dụ dưới đây là một mã kết hợp đơn giản, chuỗi bốn chuỗi.
Vì vậy, nếu str1
là null
nó sẽ cố gắng str2
, nếu str2
là null
nó sẽ cố gắng str3
và vân vân cho đến khi nó tìm thấy một chuỗi với một giá trị khác null.
string final = str1 ?? str2 ?? str3 ?? str4;
Nói một cách đơn giản, toán tử Coalescing trả về giá trị NON-NULL đầu tiên từ một chuỗi.
Đó là bàn tay ngắn cho các nhà điều hành ternary.
FormsAuth = (formsAuth != null) ? formsAuth : new FormsAuthenticationWrapper();
Hoặc cho những người không làm ternary:
if (formsAuth != null)
{
FormsAuth = formsAuth;
}
else
{
FormsAuth = new FormsAuthenticationWrapper();
}
!= null
) và thứ hai formsAuth
(sau ?
) đều có thể bị thay đổi; ở dạng hợp nhất null, cả hai đều lấy các giá trị bạn đã cung cấp.
Nếu bạn quen thuộc với Ruby, nó ||=
có vẻ giống với C # ??
đối với tôi. Đây là một số Ruby:
irb(main):001:0> str1 = nil
=> nil
irb(main):002:0> str1 ||= "new value"
=> "new value"
irb(main):003:0> str2 = "old value"
=> "old value"
irb(main):004:0> str2 ||= "another new value"
=> "old value"
irb(main):005:0> str1
=> "new value"
irb(main):006:0> str2
=> "old value"
Và trong C #:
string str1 = null;
str1 = str1 ?? "new value";
string str2 = "old value";
str2 = str2 ?? "another new value";
x ||= y
desugars cho một cái gì đó giống như x = x || y
, vì vậy ??
thực sự giống với đồng bằng ||
trong Ruby.
??
chỉ quan tâm về null
, trong khi các ||
nhà điều hành trong Ruby, như trong hầu hết các ngôn ngữ, khoảng hơn null
, false
hoặc bất cứ điều gì có thể được coi là một boolean với giá trị false
(ví dụ như trong một số ngôn ngữ, ""
). Đây không phải là một điều tốt hay xấu, chỉ đơn thuần là một sự khác biệt.
Không có gì nguy hiểm về điều này. Trong thực tế, nó là đẹp. Bạn có thể thêm giá trị mặc định nếu đó là mong muốn, ví dụ:
MÃ
int x = x1 ?? x2 ?? x3 ?? x4 ?? 0;
int? x1 = null;
Có đúng không
x1
- x4
PHẢI là loại không có giá trị : thật vô nghĩa khi nói, "kết quả là 0
nếu đó x4
là một giá trị mà nó không thể lấy được" ( null
). "Loại không thể" ở đây bao gồm cả loại giá trị null và loại tham chiếu, tất nhiên. Đó là lỗi thời gian biên dịch nếu một hoặc nhiều biến được xâu chuỗi (trừ biến cuối cùng) không thể rỗng.
Như đã chỉ ra một cách chính xác trong nhiều câu trả lời là "toán tử hợp nhất null" ( ?? ), nói về điều đó bạn cũng có thể muốn kiểm tra anh em họ của nó là "Toán tử có điều kiện Null" ( ?. Hoặc ? [ ) Là một toán tử mà nhiều lần nó được sử dụng kết hợp với ??
Được sử dụng để kiểm tra null trước khi thực hiện thao tác truy cập thành viên ( ?. ) Hoặc chỉ mục ( ? [ ). Các toán tử này giúp bạn viết ít mã hơn để xử lý kiểm tra null, đặc biệt là giảm dần vào cấu trúc dữ liệu.
Ví dụ:
// if 'customers' or 'Order' property or 'Price' property is null,
// dollarAmount will be 0
// otherwise dollarAmount will be equal to 'customers.Order.Price'
int dollarAmount = customers?.Order?.Price ?? 0;
Cách cũ mà không có ? và ?? làm điều này là
int dollarAmount = customers != null
&& customers.Order!=null
&& customers.Order.Price!=null
? customers.Order.Price : 0;
đó là dài dòng và cồng kềnh.
Chỉ để giải trí của bạn (biết bạn là tất cả các chàng trai C # ;-).
Tôi nghĩ nó bắt nguồn từ Smalltalk, nơi nó đã tồn tại nhiều năm. Nó được định nghĩa ở đó là:
trong đối tượng:
? anArgument
^ self
trong UndiniteObject (còn gọi là lớp của nil):
? anArgument
^ anArgument
Có cả phiên bản đánh giá (?) Và không đánh giá (??) về điều này.
Nó thường được tìm thấy trong các phương thức getter cho các biến riêng tư (ví dụ) lười biếng, được để lại cho đến khi thực sự cần thiết.
Một số ví dụ ở đây về việc nhận các giá trị sử dụng liên kết là không hiệu quả.
Những gì bạn thực sự muốn là:
return _formsAuthWrapper = _formsAuthWrapper ?? new FormsAuthenticationWrapper();
hoặc là
return _formsAuthWrapper ?? (_formsAuthWrapper = new FormsAuthenticationWrapper());
Điều này ngăn cản đối tượng được tái tạo mỗi lần. Thay vì biến riêng còn lại null và một đối tượng mới được tạo trên mỗi yêu cầu, điều này đảm bảo biến riêng được gán nếu đối tượng mới được tạo.
??
đánh giá ngắn? new FormsAuthenticationWrapper();
được đánh giá nếu và chỉ khi _formsAuthWrapper
là con số không.
Tôi đã đọc toàn bộ chủ đề này và nhiều chủ đề khác nhưng tôi không thể tìm thấy câu trả lời thấu đáo như thế này.
Qua đó tôi hoàn toàn hiểu được "tại sao nên sử dụng ?? và khi nào nên sử dụng ?? và cách sử dụng ??."
Nền tảng giao tiếp Windows được phát hành bởi Craig McMurtry ISBN 0-672-32948-4
Có hai trường hợp phổ biến trong đó người ta muốn biết liệu một giá trị đã được gán cho một thể hiện của một loại giá trị hay chưa. Đầu tiên là khi thể hiện một giá trị trong cơ sở dữ liệu. Trong trường hợp như vậy, người ta muốn có thể kiểm tra thể hiện để xác định xem một giá trị có thực sự có trong cơ sở dữ liệu hay không. Tình huống khác, phù hợp hơn với chủ đề của cuốn sách này, là khi thể hiện đại diện cho một mục dữ liệu nhận được từ một số nguồn từ xa. Một lần nữa, người ta muốn xác định từ trường hợp liệu một giá trị cho mục dữ liệu đó có được nhận hay không.
.NET Framework 2.0 kết hợp một định nghĩa kiểu chung cung cấp cho các trường hợp như thế này trong đó người ta muốn gán null cho một thể hiện của một loại giá trị và kiểm tra xem giá trị của thể hiện đó có phải là null không. Định nghĩa loại chung đó là System.Nullable, ràng buộc các đối số loại chung có thể được thay thế cho T thành các loại giá trị. Thể hiện của các loại được xây dựng từ System.Nullable có thể được gán một giá trị null; thật vậy, giá trị của chúng là null theo mặc định. Do đó, các loại được xây dựng từ System.Nullable có thể được gọi là các loại giá trị nullable. System.Nullable có một thuộc tính, Giá trị, theo đó giá trị được gán cho một thể hiện của một loại được xây dựng từ nó có thể được lấy nếu giá trị của thể hiện không phải là null. Do đó, người ta có thể viết:
System.Nullable<int> myNullableInteger = null;
myNullableInteger = 1;
if (myNullableInteger != null)
{
Console.WriteLine(myNullableInteger.Value);
}
Ngôn ngữ lập trình C # cung cấp một cú pháp viết tắt để khai báo các kiểu được xây dựng từ System.Nullable. Cú pháp đó cho phép một người viết tắt:
System.Nullable<int> myNullableInteger;
đến
int? myNullableInteger;
Trình biên dịch sẽ ngăn người ta cố gắng gán giá trị của loại giá trị null cho loại giá trị thông thường theo cách này:
int? myNullableInteger = null;
int myInteger = myNullableInteger;
Nó ngăn người ta làm như vậy bởi vì loại giá trị nullable có thể có giá trị null, mà nó thực sự sẽ có trong trường hợp này và giá trị đó không thể được gán cho loại giá trị thông thường. Mặc dù trình biên dịch sẽ cho phép mã này,
int? myNullableInteger = null;
int myInteger = myNullableInteger.Value;
Câu lệnh thứ hai sẽ khiến ngoại lệ bị ném vì mọi nỗ lực truy cập vào thuộc tính System.Nullable.Value là một hoạt động không hợp lệ nếu loại được xây dựng từ System.Nullable chưa được gán giá trị T hợp lệ, điều này không xảy ra trong trường hợp này trường hợp
Một cách thích hợp để gán giá trị của loại giá trị nullable cho loại giá trị thông thường là sử dụng thuộc tính System.Nullable.HasValue để xác định xem giá trị hợp lệ của T có được gán cho loại giá trị null hay không:
int? myNullableInteger = null;
if (myNullableInteger.HasValue)
{
int myInteger = myNullableInteger.Value;
}
Một tùy chọn khác là sử dụng cú pháp này:
int? myNullableInteger = null;
int myInteger = myNullableInteger ?? -1;
Theo đó, số nguyên thông thường myInteger được gán giá trị của số nguyên nullable "myNullableInteger" nếu giá trị sau được gán một giá trị số nguyên hợp lệ; mặt khác, myInteger được gán giá trị -1.
Đó là một toán tử hợp nhất null hoạt động tương tự như một toán tử ternary.
a ?? b => a !=null ? a : b
Một điểm thú vị khác cho điều này là, "Một loại không thể có thể chứa một giá trị hoặc nó có thể không được xác định" . Vì vậy, nếu bạn cố gắng gán loại giá trị nullable cho loại giá trị không nullable, bạn sẽ gặp lỗi thời gian biên dịch.
int? x = null; // x is nullable value type
int z = 0; // z is non-nullable value type
z = x; // compile error will be there.
Vì vậy, để làm điều đó bằng cách sử dụng ?? nhà điều hành:
z = x ?? 1; // with ?? operator there are no issues
FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();
tương đương với
FormsAuth = formsAuth != null ? formsAuth : new FormsAuthenticationWrapper();
Nhưng điều thú vị về nó là bạn có thể xâu chuỗi chúng, như những người khác đã nói. Một điểm yếu không thể chạm tới là bạn thực sự có thể sử dụng nó để ném ngoại lệ.
A = A ?? B ?? throw new Exception("A and B are both NULL");
Các ??
nhà điều hành được gọi là các nhà điều hành null-coalescing. Nó trả về toán hạng bên trái nếu toán hạng không rỗng; nếu không, nó trả về toán hạng bên phải.
int? variable1 = null;
int variable2 = variable1 ?? 100;
Đặt variable2
thành giá trị của variable1
, nếu variable1
KHÔNG rỗng; mặt khác, nếu variable1 == null
, đặt variable2
thành 100.
Những người khác đã mô tả Null Coalescing Operator
khá tốt. Đối với những người quan tâm, có một cú pháp rút gọn trong đó (câu hỏi SO):
FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();
tương đương với điều này:
FormsAuth ??= new FormsAuthenticationWrapper();
Một số tìm thấy nó dễ đọc và cô đọng hơn.