'Var' và toán tử hợp nhất null nên bao xa '??' được giải trí mà không cản trở khả năng đọc?


23

Tôi biết tiêu đề của câu hỏi rất chủ quan, nhưng tôi đã phải đối mặt với việc sử dụng ??toán tử bởi các đồng nghiệp của mình, trong đó cùng lúc tôi không hài lòng / thoải mái khi áp dụngvar mới sắp tới.

Đối số được đưa ra để sử dụng ?? toán tử là, nó sẽ lấy đi tính dễ đọc trong mã.

Câu hỏi của tôi là, không phải điều tương tự xảy ra khi bạn bắt đầu sử dụng var?


49
Nếu một "nhà phát triển" không thể hiểu ??toán tử hợp nhất null sau khi được giải thích, thì họ không được phép gần mã sản xuất.
CaffGeek

12
Tôi đề nghị chúng ta thay đổi toán tử từ ?? đến IfNullThen. ? có thể là IfSoChoose ,: là ElseChoose. + là Thêm. - là Subtract, trừ khi nó là unary, thì nó là phủ định. - được phân chia giữa DecrementB BeforeUsing và DecrementAfterUsing. Trong C ++, bạn có thể làm điều này với các macro.
Lee Louviere

7
@Xaade: Thật trớ trêu phải không? ... đúng? ... Chúa cho nó thật trớ trêu (và tôi là người vô thần).
Steven Jeuris

10
@StevenJeuris Nó có thể là châm biếm , nhưng nó không trớ trêu .
Kirk Broadhurst

1
@KirkBroadhurst: Tôi đứng chính xác , luôn luôn nhầm lẫn hai điều đó.
Steven Jeuris

Câu trả lời:


53

Toán tử hợp nhất Null (??)

Cá nhân, tôi không thấy bất kỳ nhược điểm nào khi sử dụng toán tử này. Hãy xem xét ba mẫu mã sau đây, từ các toán tử mới 'dễ' đến 'phức tạp'.

Không có phép thuật:

bool isNameSet = false;
string name;
if ( isNameSet )
{
    Console.WriteLine( name );
}
else
{
    Console.WriteLine( "No name set." );
}

Toán tử ternary:

bool isNameSet = false;
string name;
Console.WriteLine( isNameSet ? name : "No name set." );

Không hợp nhất:

string name = null;
Console.WriteLine( name ?? "No name set." );

Lý do các toán tử này được phát minh là vì chúng đại diện cho các hoạt động lập trình rất phổ biến . Không muốn sử dụng chúng bởi vì bạn không quen với chúng chỉ là bướng bỉnh . Ngôn ngữ phát triển, tính năng phát triển, học cách sử dụng chúng!

từ khóa var

Tôi có một ý kiến ​​hơi khác về từ khóa var. Loại biến thường cung cấp thêm thông tin về mã của bạn. Tôi thấy việc ẩn kiểu bằng cách sử dụng từ khóa var đôi khi làm cho mã ít đọc hơn. Bạn biết ít hơn những gì mong đợi mà không cần sử dụng hoàn thành tự động hoặc di chuột qua các định danh để xem chúng thực sự là gì. Theo tôi, điều này dẫn đến mã chậm hơn để đọc / ghi.

Tôi sử dụng từ khóa khi tôi thấy rằng loại không cung cấp thêm thông tin.

  • Chủ yếu trong các vòng lặp foreach , mà tôi đã học được từ Resharper vì nó là một thiết lập ở đó. Hầu hết thời gian, bạn biết loại bộ sưu tập bạn đang đi qua, vì vậy bạn biết bạn đang mong đợi các mục từ trong bộ sưu tập đó.
  • Linq truy vấn . Kết quả của các truy vấn linq thường là các loại chung rất phức tạp. Hiển thị loại này có hại nhiều hơn tốt.
  • Các kiểu chữ dài được khởi tạo đơn giản với hàm tạo của chúng. Bạn đã có thể biết loại này là gì bằng cách nhìn vào hàm tạo.

Để làm ví dụ cho tuyên bố cuối cùng:

ThisIsSomeSpecializedTypeRightHere duplication =
    new ThisIsSomeSpecializedTypeRightHere();
var justAsReadable =
    new ThisIsSomeSpecializedTypeRightHere();  // Less duplication.

// But I still prefer the following ...
int number = 9;
SomeCreatedType foo = Factory.CreateSomeType();

24
Ví dụ cuối cùng đó chính xác là khi từ khóa var có thể xuất sắc. Hãy tưởng tượng rằng mã được rải rác trong mã của bạn. Factory.CreateSomeTypetrả lại IEnumerable<SomeType>. Một ngày, vì bất cứ lý do gì, nó thay đổi để trở lại SomeType[]. Nếu bạn đã sử dụng var, nó chỉ là một biên dịch lại.
pdr

1
Lấy ví dụ đó sai cách xung quanh và sau đó đi tìm thức ăn. Numpty! Một ví dụ tốt hơn sẽ được sử dụng của bạn. Điều gì nếu Factory.CreateSomeType()thay đổi để trả lại một ISomeType?
pdr

4
@pdr: Điều đó rất có thể có nghĩa là giao diện cũng thay đổi và hành vi cũng cần được điều chỉnh / thêm vào. Nếu đó là một sự đổi tên đơn giản, bạn có thể tự động đổi tên. Nếu 'hợp đồng' thay đổi, tôi thà thấy mã của mình bị phá vỡ để tôi có thể xem liệu tôi có phải điều chỉnh thứ gì đó hay không.
Steven Jeuris

2
Tôi nghĩ nhiều khả năng là nếu trả về một loại cụ thể sẽ trở lại một giao diện mà nó chỉ cho phép các loại cụ thể khác có cùng giao diện (phù hợp với mẫu Factory). Nhưng nếu hợp đồng thay đổi thì mã của bạn sẽ bị hỏng - mặc dù bạn có thể thấy nó chỉ bị phá vỡ trong một vài trường hợp quan trọng hơn là ở mọi nơi.
pdr

1
@Tom Hawtin, tất cả chúng ta đều biết rằng không thể tránh khỏi nullhoàn toàn. Hơn nữa, tôi càng tìm kiếm các lựa chọn thay thế null, tôi càng nhận ra việc sử dụng nullđôi khi là giải pháp sạch nhất. Ví dụ đưa ra của tôi không phải là IMHO tồi tệ và tôi thấy đó là cách sử dụng phù hợp của các loại nullable.
Steven Jeuris

16

var cho phép mã verbose ít hơn, làm tăng khả năng đọc. Theo tôi, khả năng đọc không nên được đo lường bằng bao nhiêu chi tiết bạn nhìn thấy, nhưng có bao nhiêu chi tiết bị ẩn trong cái nhìn đầu tiên. Ngoài các ví dụ Linq, var cho phép gõ vịt ở cấp mã nguồn, đưa ra ví dụ sau:

...
foreach (var message in messages) {
  var label = Factory.CreateLabel();
  label.Text = message;
  Controls.Add(label);
}
...

Ai quan tâm loại nhãn là gì miễn là nó cung cấp thuộc tính Text?


Ai đó đang cố gắng để hiểu liệu đây là ví dụ như nhãn winforms hay nhãn WPF.
Steven Jeuris

14
@Steven Jeuris: đó thường là thông tin bối cảnh đã biết. Nếu không, bạn đang tiếp cận mã sai cách.
Codism

Ai đó muốn biết liệu đó là nhãn WPF mặc định hay nhãn tùy chỉnh nào đó? :)
Steven Jeuris

14
1. Người đó có thực sự quan tâm, miễn là đó là nhãn có thuộc tính Văn bản? 2. Nếu đây là một trong những trường hợp hiếm hoi mà họ THỰC SỰ CÓ lý do chính đáng để quan tâm, hãy hỏi Intellisense. 3. Nếu họ đang chỉnh sửa mã trong IDE mà không có Intellisense, họ có thể có những bất tiện lớn hơn so với 'var' :)
KutuluMike

4
Một người có ý thức trừu tượng kém.
Jim Balter

16

Tôi không có bất kỳ nhận xét nghiêm túc nào về ??nhà điều hành, vì tôi chưa bao giờ sử dụng ngôn ngữ với nhà điều hành như vậy. Về var, mọi người lập trình bằng các ngôn ngữ như Ruby, Python, Perl và PHP đã hoàn toàn nhập vào mọi lúc. Người bản địa của các ngôn ngữ này nhận ra rằng loại chính thức của một biến thường là tiếng ồn không liên quan. Bạn quan tâm nhiều hơn đến những gì biến có thể làm , tức là giao diện cấu trúc / vịt.

Tương tự, tôi lập trình chủ yếu ở D. D được gõ tĩnh nhưng có autotừ khóa, tương đương vớivar . Nó được coi là thành ngữ để sử dụng nó ở mọi nơi trừ khi bạn thấy một nhu cầu cụ thể để nhấn mạnh loại của một cái gì đó cho người đọc hoặc (thông qua chuyển đổi ngầm) trình biên dịch. Ngoại trừ thỉnh thoảng khi được sử dụng làm kiểu trả về hàm (điều này được cho phép trong D), tôi chưa bao giờ thấy nó cản trở khả năng đọc, bởi vì tôi chủ yếu nghĩ về giao diện cấu trúc / vịt, không phải kiểu chính thức / chỉ định, khi tôi lập trình.

Hơn nữa, IMHO sử dụng varmọi nơi có thể là một ví dụ điển hình về DRY. Loại của một cái gì đó nên được chỉ định ở một và chỉ một nơi, và sau đó tự động được truyền bá bất cứ khi nào nó cần được truyền bá. Nếu bạn sử dụng varvà loại chính thức của biến cần thay đổi tại một số điểm, các thay đổi cần thiết sẽ tự động được phổ biến ở mọi nơi cần thiết bởi trình biên dịch miễn là chương trình vẫn đúng kiểu, thay vì lập trình viên phải thay đổi thủ công mọi trường hợp . Đây là một điều tốt (TM).


13

Tôi nghĩ rằng đây là một câu hỏi cho đội cuối cùng. Nếu không ai có thể đọc được cho bất kỳ ai khác trong nhóm của tôi thì tôi sẽ không sử dụng nó, mặc dù tôi có thể thử một vài lần để thuyết phục họ bằng các ví dụ hoặc bằng cách chỉ ra các chữ viết tắt hậu môn (như + =) mà họ thấy dễ đọc hơn.

Tuy nhiên, nếu làm việc một mình thì tôi thấy ?? và var có thể đọc được mà không có giới hạn. Cũng

var a = b ?? c ?? d ?? e ?? "";

là khá rõ ràng đối với tôi.

Tất nhiên các nhà khai thác và dynamiclà một vấn đề khác nhau.


4
Tôi sẽ sử dụng `String.Empty 'ở đây.
Công việc

1
@Job, thành thật mà nói, tôi cũng vậy. Tôi sẽ đặt một cái gì đó vào chuỗi đó, sau đó không thể nghĩ gì cả :)
pdr

4
var a = b ?? c ?? d ?? e ?? String.Empty ?? "";
Lee Louviere

2
@Xaade Bạn không bao giờ có thể chắc chắn đủ. Nhưng thực sự, sử dụng String.Empty hoặc "" là một sở thích cá nhân. Tôi sử dụng "" vì nó ngắn hơn ...
Carra

12
@Xaade - nếu String.Emptybao giờ quay trở lại null, chúng ta đang ở trong một địa ngục của rất nhiều mã bị hỏng.
Jesse C. Choper

10

Đối số được đưa ra để sử dụng ?? toán tử là, nó lấy đi khả năng đọc trong mã.

Suy nghĩ ngắn gọn về nó, bình luận này cho tôi biết người bình luận, không hiểu nó cũng như anh ấy / cô ấy nên. Điều này rất có thể đúng trong một số trường hợp nhất định, nhưng về tổng thể, tôi không giảm giá một cái gì đó mà nhóm C # rõ ràng nghĩ là đủ quan trọng để thêm vì "khả năng đọc". Tôi đặt này trong cùng một chủng loại if(boolean_object)vs if(boolean_object == true). Một số người cho rằng cái thứ hai dễ đọc hơn, nhưng thực tế nó chỉ cần thêm mã cho ai đó đọc / gõ, và trong một số tình huống có thể gây nhầm lẫn hơn (nghĩ if(boolean_object != false))

Câu hỏi của tôi là, điều tương tự không xảy ra khi bạn bắt đầu sử dụng var?

Nhóm C # đã cho phép bạn không xác định điều gì đó mà bạn biết nó sẽ diễn ra. Trừ khi tôi thực sự cần xác định một biến sẽ là gì (hoặc điều cực kỳ quan trọng là một đối tượng trả về thuộc loại x, hoặc nó thực sự không thể đọc được), tôi sử dụng var. var x = "MY_STRING";Tôi biết đó là một chuỗi từ nhìn vào nó. Trong thực tế, tôi không thực sự quan tâm rằng đó là một chuỗi miễn là nó làm những gì tôi cần nó để làm. Xác định loại biến là vì lợi ích của tôi, không phải của trình biên dịch. Nếu có gì đó không đúng, trình biên dịch sẽ cho tôi biết khi nào nó chạy nếu tôi có loại biến sai.


0

Theo tôi, vartừ khóa được sử dụng tốt nhất trong các tình huống được giới thiệu ban đầu - truy vấn LINQ. Trong các truy vấn này, loại kết quả được trả về thường có một số tên phức tạp lớn, khó xác định trước thời hạn và không giúp người đọc hiểu được mã của bạn làm gì.

Tuy nhiên, làm var text = "Some text " + variableName + "some more text."chỉ là lười biếng.

EDIT: @Jorg Bạn đã nhảy vào một câu trả lời có mục đích đơn giản nhưng không thêm gì vào cuộc thảo luận. OK, làm thế nào về điều này cho một ví dụ tốt hơn: var items = doc.DocumentElement.FirstChild.ChildNodes;Nếu bạn có thể tìm ra loại từ đó tôi sẽ cung cấp cho bạn một cookie.


18
Nếu bạn không thể hiểu đó "Some text "là một string, thì bạn có vấn đề lớn hơn nhiều so với số lượng vars trong mã của bạn.
Jörg W Mittag

3
Vấn đề không phải là var; vấn đề là tên "mặt hàng" crappy. Nếu bạn sử dụng một tên biến tốt, không có gì sai với var.
Kyralessa

3
Tôi đoán (không cần tìm) các mục đó là một tập hợp các nút XML, mà tôi mong đợi có tất cả các thuộc tính và phương thức của một tập hợp các nút XML và đó thực sự là tất cả những gì tôi cần biết.
KutuluMike

Nếu bạn cần biết var là viết tắt của từ gì và không thể biết ngay lập tức bằng cách nhìn, chỉ cần di chuột qua nó. Không mất nhiều công sức để làm điều đó.
Scrwtp

1
"Chỉ là lười biếng" - Đây không phải là một lập luận chống lại nó. Trên thực tế, nó hoàn toàn không thông minh.
Jim Balter

0

Tôi có một vấn đề cơ bản với việc sử dụng var.

Trong ví dụ này, mọi thứ đều song song, nhưng vấn đề thực sự là với các giải pháp lớn với các thư viện hoặc dự án chung.

Xem xét điều này:

public MyFirstObject GetMeAnObject() {
    return new MyFirstObject();
}

public void MainProgram() {
    var theObject = GetMeAnObject();
    theObject.PerformOperation();
}

Điều gì xảy ra nếu người khác thay đổi GetMeAnObject để phù hợp với nhu cầu của họ?

public MySecondObject GetMeAnObject() {
    return new MySecondObject();
}

Phương thức MainProgram sẽ có một lỗi lớn màu đỏ trên .PerformOperation (). Chuyện gì đã xảy ra? PerformanceOperation hoạt động hoàn hảo trước đây. Chúng tôi xem xét các phương thức trên theObject và nó chỉ biến mất không một dấu vết. Nó đã ở đó lần trước, và chúng tôi cần phương pháp đó. Bạn có thể mất một thời gian dài để theo đuổi cái đuôi của mình và cố gắng tìm hiểu tại sao, nếu MyFirstObject có một phương thức gọi là PerformanceOperation, thì bây giờ không thể nhìn thấy nó. Mọi người "biết" rằng GetMeAnObject trả về MyFirstObject, vì vậy không có điểm nào kiểm tra điều đó.

Nếu bạn đã gõ rõ ràngObject thì bạn sẽ gặp lỗi Cast không hợp lệ trên dòng gọi GetMeAnObject và rõ ràng là GetMeAnObject sẽ trả về một loại không như bạn mong đợi.

Tóm lại, khai báo rõ ràng có nghĩa là bạn biết ý nghĩa của các lỗi. Truyền không hợp lệ có nghĩa là bạn mong đợi một loại và một loại khác đã được trả lại. Một thành viên không được công nhận có nghĩa là thành viên không được công nhận.


10
Một đồng nghiệp đã thực hiện một thay đổi đột phá trong mã không được kiểm tra và bạn nghĩ vấn đề là vargì? Ngôn ngữ không thể được mong đợi để bảo vệ chống lại loại hành vi đó - điều gì xảy ra nếu họ đã sửa đổi trực tiếp MyFirstObject? Nó vẫn sẽ bị hỏng, nhưng không có cú pháp nào có thể cứu bạn khỏi điều đó. Tôi sẽ coi đây là một thế mạnh của var, thậm chí: nếu thay vì trả lại MySecondObject thì bây giờ bạn đang trả lại IMyFirstObject thì sao?
Phoshi

2
"Mọi người" đều biết rằng GetMeAnObject trả về MyFirstObject, vì vậy không có điểm nào kiểm tra điều đó. " Tôi thực sự không thể nghĩ ra một kịch bản trong lập trình mà tôi thực sự sẽ phụ thuộc vào trí nhớ của mình về những gì GetMeAnObject nếu tôi gỡ lỗi. Nếu tôi kiểm tra rằng PerformanceOperation không có ở đó, tôi sẽ thấy mã và không có mã nào cho lớp khác. Nếu trong một IDE, lớp sẽ bật lên ví dụ tôi nhìn vào loại đối tượng. Trên thực tế, khi trình biên dịch báo lỗi cho tôi, nó sẽ báo 'lớp MySecondObject không có hoạt động PerformanceOperation'. Làm thế nào là cho mọi người biết?
Muhammad Alkarouri
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.