Kiểm tra nếu một phương thức trả về false: gán kết quả cho biến tạm thời, hoặc đặt lời gọi phương thức trực tiếp trong điều kiện?


9

Đó có phải là một cách thực hành tốt để gọi một phương thức trả về giá trị đúng hay sai trong câu lệnh if?

Một cái gì đó như thế này:

private void VerifyAccount()
{
    if (!ValidateCredentials(txtUser.Text, txtPassword.Text))
    {
        MessageBox.Show("Invalid user name or password");
    }
}

private bool ValidateCredentials(string userName, string password)
{
    string existingPassword = GetUserPassword(userName);
    if (existingPassword == null)
        return false;

    var hasher = new Hasher { SaltSize = 16 };
    bool passwordsMatch = hasher.CompareStringToHash(password, existingPassword);

    return passwordsMatch;
}

hoặc tốt hơn là lưu trữ chúng trong một biến sau đó so sánh chúng bằng cách sử dụng các giá trị khác như thế này

bool validate = ValidateCredentials(txtUser.Text, txtPassword.Text);
if(validate == false){
    //Do something
}

Tôi không chỉ đề cập đến .NET, tôi đang đề cập đến câu hỏi trong tất cả các ngôn ngữ lập trình, nó chỉ xảy ra rằng tôi đã sử dụng .NET làm ví dụ


3
Nếu bạn sử dụng một biến tạm thời, hãy viết if (!validate)chứ không phải if (validate == false).
Philip

12
Tôi sẽ đặt tên cho hàm này là "CredentialsAreValid ()" để bạn biết rằng nó sẽ trả về một bool nhưng nếu không thì thực tế tốt của nó
Zachary K

3
IsValidCredentials, mặc dù lúng túng về mặt ngữ pháp, là một định dạng phổ biến để chỉ ra giá trị trả về boolean.
zzzzBov

@Philip sự khác biệt giữa if (! Xác thực) và điều này nếu (xác thực) ??
KyelJmD

!là toán tử "KHÔNG", nó phủ nhận bất kỳ biểu thức boolean nào. Như vậy if (!validate)là ngược lại if (validate). Câu lệnh if sẽ được nhập nếu validatekhông đúng.
Philip

Câu trả lời:


26

Như với tất cả những điều này, nó phụ thuộc.

Nếu bạn sẽ không sử dụng kết quả cuộc gọi của mình ValidateCredentialsthì không cần (ngoài mục đích gỡ lỗi) để lưu trữ kết quả trong một biến cục bộ. Tuy nhiên, nếu nó làm cho mã dễ đọc hơn (và do đó dễ bảo trì hơn) để có một biến đi theo đó.

Mã sẽ không hiệu quả hơn.


1
Đó là loại có thể đọc được? giống như tôi đã làm ở trên
KyelJmD

@KyelJmD: Điều đó phụ thuộc vào văn hóa bạn đang lập trình. Ở những nơi tôi đã lập trình, !ValidateCredentialscàng dễ đọc hơn vì nó nói rõ ràng những gì nó đang làm trong mã. Nó rất rõ ràng. Nếu chức năng bạn đang gọi không có tên "tự ghi lại" thì có thể tốt hơn là đi với biến. Vì thế, tôi khuyên bạn nên bỏ qua biến và giữ nguyên mã tự ghi mà bạn có.
Joel Etherton 7/12/2015

Xác thực không thể đọc được ở vị trí đầu tiên - tên này cho bạn biết kết quả như thế nào? Tốt hơn nhiều là CredentialsAreValid hoặc CredentialsAreInvalid.
gnasher729

9

Tại sao sử dụng một biến bổ sung? Tôi thích sử dụng cách tiếp cận đầu tiên, nó dễ đọc và đơn giản hơn.


4

Đó có phải là một cách thực hành tốt để gọi một phương thức trả về giá trị đúng hay sai trong câu lệnh if?

Có, nếu điều kiện không đủ đơn giản để nội tuyến và có thể đọc được.

hoặc tốt hơn là lưu trữ chúng trong một biến sau đó so sánh chúng bằng cách sử dụng các giá trị khác như thế này

Bạn chỉ nên làm điều này nếu bạn sử dụng giá trị ở nhiều nơi hoặc cần nó để làm cho mã dễ đọc hơn. Nếu không, việc gán cho một biến là không cần thiết. Mã không cần thiết là lãng phí tốt nhất và tồi tệ nhất là một nguồn khiếm khuyết.


2

Để xem...

Bởi vì đó là tất cả về KISS , không cần tạo thêm một biến khi bạn có thể làm mà không cần đến nó. Ngoài ra, không cần phải gõ thêm ... khi không có nhu cầu.

Nhưng sau đó vì bạn KHÔ , nếu sau đó bạn gọi điện ValidateCredentialsvà thấy mình đang gõ thì ValidateCredentials(txtUser.Text, txtPassword.Text)bạn biết rằng bạn nên tạo một biến bổ sung.


2

Có, thường sử dụng các phương pháp như vậy là điều kiện. Nó rất hữu ích mặc dù nếu tên phương thức chỉ ra rằng phương thức trả về một bool; ví dụ CanValidateCredentials. Trong các ngôn ngữ kiểu C, phương thức này thường có dạng tiền tố Is và Can và trong Ruby có '?' hậu tố.


1
Điểm hay về tên phương thức, nhưng tôi sẽ không bao giờ bắt đầu tên phương thức bằng "if". Sau đó, mã đọc "nếu nếu". "Có thể" là ok : if (cat.canOpenCanOfCatFood()).
kevin cline

Cảm ơn, @Kevin. Tôi có nghĩa là 'Không phải' Nếu '. Tôi đã chỉnh sửa câu trả lời
Christian Horsdal

1

Có một mối quan tâm khác chưa được chỉ ra: đánh giá ngắn mạch . Sự khác biệt giữa hai đoạn mã này là gì?

Vd # 1:

if(foo() && bar() && baz())
{
    quz();
}

Vd # 2:

bool isFoo = foo();
bool isBar = bar();
bool isBaz = baz();
if(isFoo && isBar && isBaz)
{
    quz();
}

Hai đoạn mã này dường như làm cùng một việc, nhưng nếu ngôn ngữ của bạn hỗ trợ đánh giá ngắn mạch, hai đoạn này là khác nhau. Đánh giá ngắn mạch có nghĩa là mã sẽ đánh giá mức tối thiểu cần thiết để vượt qua hoặc thất bại một điều kiện. Nếu ví dụ # 1, nếu foo () trả về false, bar () và baz () thậm chí không được đánh giá. Điều này hữu ích nếu baz () là một lệnh gọi hàm dài vì bạn có thể bỏ qua nếu foo () trả về false hoặc foo () trả về true và bar () trả về false.

Đây không phải là trường hợp trong ví dụ # 2. foo (), bar () và baz () luôn được đánh giá. Nếu bạn đang mong đợi thanh () và baz () thể hiện tác dụng phụ, bạn sẽ gặp vấn đề với Ví dụ # 1. Ví dụ # 1 ở trên thực sự tương đương với điều này:

Ví dụ 3:

if(foo())
{
    if(bar())
    {
        if(baz())
        {
            quz();
        }
    }
}

Hãy nhận biết những khác biệt trong mã của bạn khi chọn giữa các ví dụ # 1 và # 2.


1

Mở rộng một chút về vấn đề dễ đọc ...

Tôi có thể nghĩ ra hai lý do tốt để lưu trữ kết quả trong một biến:

  1. Nếu bạn sẽ sử dụng điều kiện nhiều lần, lưu nó vào một biến có nghĩa là bạn chỉ phải gọi hàm một lần. (Điều này giả định rằng giá trị được lưu trữ vẫn còn hiệu lực; nếu bạn cần kiểm tra lại, tất nhiên điều này không áp dụng.)

  2. Nếu lưu trữ nó trong một biến sẽ cải thiện khả năng đọc bằng cách đặt cho điều kiện một tên có ý nghĩa hơn so với những gì bạn thấy trong lệnh gọi hàm.

Ví dụ: cái này:

bool foo_is_ok = is_ok(foo);
if (foo_is_ok) ...

không giúp đọc được, nhưng điều này:

bool done_processing = feof(file1) && feof(file2);
if (done_processing) ...

có lẽ là như vậy, vì nó không rõ ràng ngay lập tức feof(file1) && feof(file2)có nghĩa là chúng ta đã xử lý xong.

Các passwordsMatchbiến trong câu hỏi có lẽ là một ví dụ tốt hơn so với tôi.

Các biến sử dụng một lần rất hữu ích nếu chúng đặt một tên có ý nghĩa cho một số giá trị. (Điều này tất nhiên là vì lợi ích của người đọc.)


Tôi nghĩ, tôi thà bỏ một bình luận thay vì giới thiệu done_processingbiến. Rốt cuộc, tên done_processingphục vụ chức năng của một bình luận. Và một nhận xét thực sự cho phép tôi nói một hoặc hai từ về lý do tại sao điều kiện này báo hiệu chúng ta đã xử lý xong. Tuy nhiên, không phải tôi là một nhà bình luận tuyệt vời, có lẽ tôi không làm gì trong mã thực sự ...
cmaster - khôi phục monica

@cmaster: Một vấn đề với các bình luận là họ có thể rất dễ dàng đồng bộ hóa với mã. Một biến có tên done_processinglà một cách bền vững hơn để thể hiện ý định.
Keith Thompson

+1 cho điểm số 2 - đôi khi một varp temp có tên tốt thực sự làm rõ mọi thứ.
dùng949300
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.