2012-11-11 26 views
11

Xem xét chức năng này, mà bạn có thể nghĩ đến như một bảng sự thật:Làm cách nào để tránh trạng thái boolean không thể thực hiện được trong C#?

public Foo doSomething(bool a, bool b) { 

     if (a && b) return doAB(); 
    else if (a && !b) return doA(); 
    else if (!a && b) return doB(); 
    else if (!a && !b) return doNotANotB(); 

    else throw new Exception("Well done, you defeated boolean logic!"); 
} 

Trình biên dịch khăng khăng rằng else khoản cuối cùng. Nhưng từ quan điểm của một bảng chân lý, đó là một trạng thái không thể.

Có, nó hoạt động, và có, tôi có thể sống với nó. Nhưng tôi tự hỏi nếu có một số cơ chế trong C# để tránh loại mã này, hoặc nếu tôi đã bỏ lỡ một cái gì đó hiển nhiên?

UPDATE:
Đối với điểm thưởng, và hoàn toàn ra khỏi tò mò, là có bất kỳ ngôn ngữ mà đối phó với các loại điều này khác nhau? Có lẽ nó không phải là một vấn đề ngôn ngữ, mà là một trong những trình biên dịch thông minh (nhưng các trường hợp cạnh sẽ phức tạp không tưởng tượng được).

+6

Có, có tôi s cơ chế như vậy: chỉ cần thả điều kiện của 'if' cuối cùng. – dasblinkenlight

+0

Rất đúng! Pun dự định. Nhưng nếu có thể, tôi muốn mã được "dễ đọc" hoặc "biểu cảm". Hãy ghi nhớ đây là một ví dụ đơn giản. Và trong 7 tháng, tôi sẽ gãi đầu khi tự hỏi mình đang nghĩ gì khi viết nó (vì thế ưu tiên cho mã biểu cảm). –

+0

Nếu các hành động không liên quan đến eachother, tôi sẽ không sử dụng mẫu 'if/else if', mà thay vào đó hãy chọn bốn khối' if' riêng biệt sau khi ném ngoại lệ để thỏa mãn trình biên dịch. Tuy nhiên, trong hầu hết các trường hợp, có một hành động 'mặc định' phù hợp hoàn hảo với một 'else' trống. –

Trả lời

18

Xem xét bảng chân lý, điều kiện cuối cùng là hoàn toàn superfluos. Nó có thể được giảm mà không thay đổi logic của chương trình của bạn, như thế này:

public MyType doSomething(bool a, bool b) { 

     if (a && b) return doAB(); 
else if (a && !b) return doA(); 
else if (!a && b) return doB(); 
else/*if (!a && !b)*/ return doNotANotB(); 
} 

Bây giờ bạn có một nhận tất cả thức if, và trình biên dịch của bạn là hạnh phúc. Bạn không cần phải loại bỏ hoàn toàn điều kiện - tôi thường tìm thấy nó là một ý tưởng hay để giữ nó trong một bình luận để có thể đọc được.

+3

Tôi thực sự thích để lại mã nhận xét vì nó ghi lại điều kiện cho nhánh cuối cùng hiệu quả là gì. +1 – usr

+0

Có như tôi đã lưu ý trong phần bình luận ở trên, điều này đúng. Nhưng liệu có cách nào để tôi có thể thể hiện ý định mà không phải dùng đến những điều kiện tiềm ẩn? Có lẽ không ... –

+0

@BobbyB Tuyệt đối, đừng vội vàng! Có một cơ hội mà ai đó biết trình biên dịch C# từ bên trong thấy câu hỏi này và chia sẻ một câu trả lời sâu sắc với chúng tôi. (Tôi có nghĩa là cụ thể [Eric Lippert] (http://stackoverflow.com/users/88656/eric-lippert), mặc dù tiếc là gần đây anh ấy đã không trả lời quá nhiều câu hỏi). – dasblinkenlight

2
public MyType doSomething(bool a, bool b) 
     { 
      switch(a) 
      { 
       case true: 
        if (b) return doAB(); 
        return doA(); 
       default: 
        if (b) return doB(); 
        return doNotANotB(); 

      } 

     } 

Cập nhật:

Lưu ý rằng tuyên bố ban đầu của bạn là thực sự:

public MyType doSomething(bool a, bool b) 
     { 
      if (a && b) return doAB(); 
      if (a) return doA(); 
      if (b) return doB(); 
      return doNotANotB(); 
     } 

Đối với niềm vui và succintnes (nếu không nói là dễ đọc: p):

static MyType doSomething(bool a, bool b) 
     { 
      return a && b ? doAB() : a ? doA() : b ? doB() : doNotANotB(); 
     } 
+0

Rõ ràng là ít có thể đọc được, nhưng thực sự rất thú vị! –

+0

Tôi nghĩ tôi thích ví dụ sau. Tôi không nghĩ rằng nó là ít có thể đọc được miễn là thích hợp biến và phương pháp tên được sử dụng, và có lẽ một số newlines và thụt đầu dòng. –

+0

* Nods *, tôi thích bản thân mình mặc dù tôi nghĩ rằng nó rất dễ dàng để đi lên trên các đánh giá ternary lồng nhau. – Anthill

6

Thử f #. Nếu nó có thể phát hiện điều kiện đầy đủ phù hợp với chỉ thị khớp của nó thì nó không yêu cầu người khác.

http://ganesansenthilvel.blogspot.co.at/2011/12/f-pattern-matching.html?m=1#!

> let testAND x y = 
match x, y with 
| true, true -> true 
| true, false -> false 
| false, true -> false 
| false, false -> true 

> testAND true false;; 
val it: bool = true 

và cho một đặc điểm kỹ thuật đầy đủ

> let testAND x y = 
match x, y with 
| true, true -> true 
// Commented | true, false -> false 
| false, true -> false 
| false, false -> true 
> testAND true false;; 

trình biên dịch sẽ nói

Microsoft.Fsharp.Core.MatchFailureExcption: The match cases were incomplete at:.... 
Stopped due to error 
7
if(a) return b ? doAB() : doA(); 
else return b ? doB() : doNotAnotB(); 

Hoặc ngắn:

return a ? (b ? doAB() : doA()) 
     : (b ? doB() : doNotAnotB()); 
Các vấn đề liên quan