2008-08-28 33 views
103

Có hai nhà khai thác lạ trong C#:Toán tử giả trong C# tốt là gì?

Nếu tôi hiểu đúng này các nhà khai thác có thể được sử dụng trong các loại mà tôi muốn sử dụng thay vì một boolean biểu thức và nơi tôi không muốn cung cấp một chuyển đổi ẩn thành bool.

Hãy nói rằng tôi có một lớp học sau đây:

public class MyType 
    { 
     public readonly int Value; 

     public MyType(int value) 
     { 
      Value = value; 
     } 

     public static bool operator true (MyType mt) 
     { 
      return mt.Value > 0; 
     } 

     public static bool operator false (MyType mt) 
     { 
      return mt.Value < 0; 
     } 

    } 

Vì vậy, tôi có thể viết đoạn mã sau:

MyType mTrue = new MyType(100); 
    MyType mFalse = new MyType(-100); 
    MyType mDontKnow = new MyType(0); 

    if (mTrue) 
    { 
     // Do something. 
    } 

    while (mFalse) 
    { 
     // Do something else. 
    } 

    do 
    { 
     // Another code comes here. 
    } while (mDontKnow) 

Tuy nhiên đối với tất cả các ví dụ trên chỉ là điều hành đúng được thực thi. Vậy toán tử giả trong C# tốt là gì?

Lưu ý: Bạn có thể tìm thêm các ví dụ khác here, herehere.

+0

Tài liệu hiện đại có thể được tìm thấy tại https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/false-operator. Các tài liệu cho rằng không có lý do gì để định nghĩa toán tử này nữa vì C# 2.0 đã thêm các kiểu nullable. –

Trả lời

61

Bạn có thể sử dụng nó để ghi đè các toán tử &&||.

Các &&|| nhà khai thác không thể được ghi đè, nhưng nếu bạn ghi đè |, &, truefalse trong cách chính xác đúng trình biên dịch sẽ gọi |& khi bạn viết ||&&.

Ví dụ, nhìn vào mã này (từ http://ayende.com/blog/1574/nhibernate-criteria-api-operator-overloading - nơi tôi phát hiện ra về thủ thuật này; archived version bởi @BiggsTRC):

public static AbstractCriterion operator &(AbstractCriterion lhs, AbstractCriterion rhs) 
{ 
     return new AndExpression(lhs, rhs); 
} 

public static AbstractCriterion operator |(AbstractCriterion lhs, AbstractCriterion rhs) 
{ 
     return new OrExpression(lhs, rhs); 
} 

public static bool operator false(AbstractCriterion criteria) 
{ 
     return false; 
} 
public static bool operator true(AbstractCriterion criteria) 
{ 
     return false; 
} 

Đây rõ ràng là một tác dụng phụ và không phải là cách nó được dự định được được sử dụng, nhưng nó rất hữu ích.

+4

+1 Đó là một mẹo hay. Nice tìm! –

+0

liên kết của bạn là 404. Không chắc chắn cách bạn muốn chỉnh sửa trang này, vì vậy tôi đã để nó ở đó. – user7116

+0

Tôi đã cập nhật URL bằng một bản sao đã lưu trữ để nó vẫn có thể đọc được. – IAmTimCorey

14

Trang bạn liên kết đến http://msdn.microsoft.com/en-us/library/6x6y6z4d.aspx cho biết chúng là gì, đó là cách xử lý các khóa có giá trị trước khi loại giá trị rỗng được giới thiệu.

Tôi đoán ngày nay chúng tốt cho cùng loại công cụ như ArrayList - tức là hoàn toàn không có gì.

3

Nó xuất hiện từ bài viết MSDN bạn liên kết với nó được cung cấp để cho phép các kiểu boolean không thể thực hiện trước kiểu Nullable (tức là int ?, bool ?, v.v.) được đưa vào ngôn ngữ trong C# 2. Vì vậy, bạn sẽ lưu trữ một giá trị nội bộ cho biết giá trị là đúng hay sai hay không, tức là trong ví dụ của bạn> 0 cho true, < 0 cho false và == 0 cho null, và sau đó bạn sẽ nhận được ngữ nghĩa null kiểu SQL. Bạn cũng sẽ phải thực hiện một phương thức hoặc thuộc tính .IsNull để thứ tự null có thể được kiểm tra một cách rõ ràng.

So sánh với SQL, hãy tưởng tượng một bảng Bảng có 3 hàng có giá trị Foo được đặt thành true, 3 hàng có giá trị Foo được đặt thành false và 3 hàng có giá trị Foo được đặt thành rỗng.

SELECT COUNT(*) FROM Table WHERE Foo = TRUE OR Foo = FALSE 
6 

Để đếm tất cả các hàng bạn phải làm như sau: -

SELECT COUNT(*) FROM Table WHERE Foo = TRUE OR Foo = FALSE OR Foo IS NULL 
9 

'IS NULL' Cú pháp này sẽ có mã equivilent trong lớp học của bạn như .IsNull().

LINQ làm cho việc so sánh với C# thậm chí rõ ràng hơn: -

int totalCount = (from s in MyTypeEnumerable 
       where s || !s 
       select s).Count(); 

Tưởng tượng rằng MyTypeEnumberable có chính xác cùng một nội dung của cơ sở dữ liệu, tức là 3 giá trị bằng true, 3 giá trị tương đương với giả và 3 giá trị tương đương với vô giá trị. Trong trường hợp này totalCount sẽ đánh giá 6 trong trường hợp này. Tuy nhiên, nếu chúng tôi viết lại mã như sau: -

int totalCount = (from s in MyTypeEnumerable 
       where s || !s || s.IsNull() 
       select s).Count(); 

Sau đó totalCount sẽ đánh giá là 9.

Ví dụ DBNull được đưa ra trong bài viết MSDN được liên kết trên toán tử giả thể hiện một lớp trong BCL có hành vi chính xác này.

Kết quả là bạn không nên sử dụng điều này trừ khi bạn hoàn toàn chắc chắn rằng bạn muốn loại hành vi này, tốt hơn là chỉ sử dụng cú pháp vô giá đơn giản hơn nhiều !!

Cập nhật: Tôi vừa nhận thấy bạn cần ghi đè thủ công các toán tử logic!, || và & & để thực hiện công việc này một cách chính xác. Tôi tin rằng toán tử giả đưa vào các toán tử logic này, tức là chỉ ra sự thật, sai lệch hoặc 'ngược lại'. Như đã nói trong một bình luận khác, x sẽ không làm việc được; bạn phải quá tải! Sự kì lạ!

7

AFAIK, nó sẽ được sử dụng trong thử nghiệm cho sai, chẳng hạn như khi nhà cung cấp && hoạt động. Hãy nhớ rằng, & & ngắn mạch, vì vậy trong biểu thức

if (mFalse && mTrue) 
{ 
    // ... something 
} 

mFalse.false() được gọi, và khi trở về true biểu thức được giảm xuống một lời kêu gọi 'mFalse.true()' (mà sau đó phải trả lại false, hoặc mọi thứ sẽ trở nên kỳ lạ).

Lưu ý rằng bạn phải triển khai toán tử & để biểu thức đó biên dịch, vì nó được sử dụng nếu mFalse.false() trả lại false.

21

Shog9 và Nir: cảm ơn câu trả lời của bạn. Những câu trả lời chỉ tôi Steve Eichert article và nó chỉ cho tôi để msdn:

Các hoạt động x & & y được đánh giá là T.false (x)? x: T. & (x, y), trong đó T.false (x) là một lời gọi của toán tử false được khai báo trong T, và T. & (x, y) là một lời gọi của toán tử được chọn &. Nói cách khác, x được đánh giá đầu tiên và toán tử false được gọi trên kết quả để xác định xem x có phải là sai hay không. Sau đó, nếu x chắc chắn là sai, kết quả của phép toán là giá trị được tính trước đó cho x. Nếu không, y được đánh giá và toán tử được chọn & được gọi trên giá trị được tính trước đó cho x và giá trị được tính cho y để tạo kết quả của phép toán.

Các vấn đề liên quan