2011-06-26 38 views
10

我一直在尋找超載的false操作符實際執行的實際工作代碼。什麼時候重載的假操作符被執行,它有什麼好處?

This question (What's the false operator in C# good for?)有點相同,但接受的答案鏈接到返回404錯誤的網址。我也看過How does operator overloading of true and false work?和其他一些問題。

我在幾乎所有的答案中發現,當你使用短路和x && y時,false只會被執行。這被評估爲T.false(x) ? x : T.&(x, y)

好的,所以我有以下代碼。該struct包含int並認爲自己真要是int是大於零:

public struct MyStruct { 
    private int _i; 

    public MyStruct(int i) { 
     _i = i; 
    } 

    public static bool operator true(MyStruct ms) { 
     return ms._i > 0; 
    } 

    public static bool operator false(MyStruct ms) { 
     return ms._i <= 0; 
    } 

    public override string ToString() { 
     return this._i.ToString(); 
    } 
} 

現在我希望下面的程序將執行與使用重載false運營商。

class Program { 
    private static void Main() { 
     MyStruct b1 = new MyStruct(1); // to be considered true 
     MyStruct b2 = new MyStruct(-1); // to be considered false 

     Console.WriteLine(b1 && b2); 
     Console.WriteLine(b2 && b1); 
    } 
} 

但是,它甚至沒有編譯。它表示它不能將運算符'& &'應用於'MyStruct'和'MyStruct'類型的操作數。

我知道我可以實現&運算符的過載。所以讓我們來做。 &必須返回一個MyStruct,所以我不能讓它返回一個bool

public static MyStruct operator &(MyStruct lhs, MyStruct rhs) { 
    return new MyStruct(lhs._i & rhs._i); 
} 

現在代碼確實編譯。它的輸出是1-1。所以b1 && b2的結果與b2 && b1的結果不一樣。

如果我調試了代碼,我看到b1 && b2首先執行運營商b1,它返回false。然後它在b1和b2上執行&運算符,該運算符執行逐位和1和-1,結果爲1.所以它確實首先檢查b1是否爲假。

第二個表達式b2 && b1首先在b2上執行false運算符,該運算符返回true。結合我使用短路的事實,它不會對b1執行任何操作,只是輸出值b2

所以,當您使用短路時,false運算符會被執行。但是,它不會在第二個參數上執行truefalse運算符,而是在操作數上執行重載的&運算符。

什麼時候這可能有用?或者我怎樣才能使我的類型,以便它可以檢查兩個變量是否都是真的?

+0

你試過重載'&&'操作符嗎? – Snowbear

+0

@snowbear:你是什麼意思?你不能重載&&或||運營商。請參見[http://msdn.microsoft.com/en-us/library/8edha89s(v=VS.100).aspx](MSDN)。 – comecme

+0

@Snowbear - 這正是原創文章作者試圖完成的功能,儘管微軟不允許重載&&和||運營商。 – IAmTimCorey

回答

4

編輯 -

閱讀鏈接的文章中,我能得到下面的輸出,同時使用的真假運營商:

op false on 1 
op & on 1 -1 
op true on 1 
op true on -1 
FALSE 
op false on -1 
op true on -1 
FALSE 
op true on 1 
op true on 1 
TRUE 
op true on -1 
op & on -1 1 
op true on -1 
op true on 1 
TRUE 

隨着代碼:

class Program 
{ 
    static void Main(string[] args) 
    { 
     MyStruct b1 = new MyStruct(1); // to be considered true 
     MyStruct b2 = new MyStruct(-1); // to be considered false 

     Console.WriteLine((b1 && b2) ? "TRUE" : "FALSE"); 
     Console.WriteLine((b2 && b1) ? "TRUE" : "FALSE"); 

     Console.WriteLine((b1 || b2) ? "TRUE" : "FALSE"); 
     Console.WriteLine((b2 || b1) ? "TRUE" : "FALSE"); 

     Console.ReadLine(); 
    } 
} 

public struct MyStruct 
{ 
    private int _i; 

    public MyStruct(int i) 
    { 
     _i = i; 
    } 

    public static bool operator true(MyStruct ms) 
    { 
     Console.WriteLine("op true on {0}", ms); 
     return ms._i > 0; 
    } 

    public static bool operator false(MyStruct ms) 
    { 
     Console.WriteLine("op false on {0}", ms); 
     return ms._i <= 0; 
    } 

    public static MyStruct operator &(MyStruct lhs, MyStruct rhs) 
    { 
     Console.WriteLine("op & on {0} {1}", lhs, rhs); 

     if (lhs) 
     { 
      return rhs; 
     } 
     else 
     { 
      return new MyStruct(-1); //-1 is false 
     } 
    } 

    public static MyStruct operator |(MyStruct lhs, MyStruct rhs) 
    { 
     Console.WriteLine("op & on {0} {1}", lhs, rhs); 

     if (lhs) 
     { 
      return lhs; 
     } 
     else 
     { 
      return rhs; 
     } 
    } 

    public override string ToString() 
    { 
     return this._i.ToString(); 
    } 
} 

當你說第一個代碼無法編譯時,我不確定你的意思,雖然它不使用操作符true/false,但我運行以下代碼在2010年明確並得到了輸出:

op bool on 1 
op bool on -1 
False 
op bool on -1 
False 
op bool on -1 
op bool on 1 
True 
op bool on 1 
True 

代碼:

class Program 
{ 
    static void Main(string[] args) 
    { 
     MyStruct b1 = new MyStruct(1); // to be considered true 
     MyStruct b2 = new MyStruct(-1); // to be considered false 

     Console.WriteLine(b1 && b2); 
     Console.WriteLine(b2 && b1); 

     Console.WriteLine(b2 || b1); 
     Console.WriteLine(b1 || b2); 

     Console.ReadLine(); 
    } 
} 

public struct MyStruct 
{ 
    private int _i; 

    public MyStruct(int i) 
    { 
     _i = i; 
    } 

    public static bool operator true(MyStruct ms) 
    { 
     Console.WriteLine("op true on {0}", ms); 
     return ms._i > 0; 
    } 

    public static bool operator false(MyStruct ms) 
    { 
     Console.WriteLine("op false on {0}", ms); 
     return ms._i <= 0; 
    } 

    public static implicit operator bool(MyStruct ms) 
    { 
     Console.WriteLine("op bool on {0}", ms); 
     return ms._i > 0; 
    } 

    public override string ToString() 
    { 
     return this._i.ToString(); 
    } 
} 
+0

對不起,我沒有添加運算符'bool',直到後來。有了'bool',它確實可以編譯。我會修改我的代碼。 – comecme

+0

運算符'bool'和運算符'&'不在其中,'true'和'false'運算符永遠不會被調用。只有'bool'被調用。所以我想我可以通過使用運算符'bool'來獲得'&&'來完成我想要的操作。但是,重載'true'和'false'實際上是有用的。 – comecme

+0

我編輯了答案,使用true和false操作符來顯示它,但仍然不確定爲什麼要使用這種方法,而只是重載bool,這會更易讀。 – BrandonAGr

4

你提到了404可以在這裏找到該網址的內容:

http://web.archive.org/web/20080613013350/http://www.ayende.com/Blog/archive/2006/08/04/7381.aspx

的文章作者指的是這裏:

http://web.archive.org/web/20081120013852/http://steve.emxsoftware.com/NET/Overloading+the++and++operators

要再次避免同樣的問題,下面是文章的亮點:

幾個月前,我張貼了關於我們與它是如何工作的解釋和說明的查詢API。我們查詢API允許我們使用強類型的C#語法來表達我們的疑問:

List<Customer> customers = repository.FindAll(Customer.Columns.Age == 20 & Customer.Columns.Name == 「foo」); 

一個我在以前的文章中指出的是,我不能超載& &和東西||運營商直接,因爲框架不允許這樣的瘋狂......至少不是直接。

特別是,不可能重載成員訪問,方法調用,或運算符,這是不可能的。 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/csspec/html/vclrfcsharpspec_7_2_2.asp

在過去的一個月,我做了專題一個小調查,看看是否和如何我可以得到& &和||以我想要的方式行事。今天晚上,我遇到了MSDN上的條件邏輯運算符頁面,它給了我正在尋找的答案:

操作x & & y評估爲T.false(x)? x:T. &(x,y),其中T.false(x)是在T中聲明的運算符false的調用,並且T是&(x,y)是所選運算符&的調用。換句話說,首先對x進行評估,並對結果調用operator false以確定x是否肯定是false。那麼,如果x肯定是假的,那麼操作的結果就是先前爲x計算的值。否則,對y進行評估,並且選擇的運算符&針對之前針對x計算的值以及針對y計算的值來調用以產生操作的結果。 操作x || y被評估爲T.true(x)? x:T. |(x,y),其中T.true(x)是在T中聲明的真實運算符的調用,並且T. |(x,y)是對所選運算符|的調用。換句話說,首先計算x,然後調用operator true來確定x是否肯定爲真。那麼,如果x肯定是真的,則操作的結果是之前爲x計算的值。否則,評估y,並選擇運算符|調用先前爲x計算的值和爲y計算的值以產生操作結果。 由於我們已經有&和|運營商到位,這只是一個超負荷的真假運營商都返回假的問題。這導致&和|操作員總是被調用,這又導致兩個標準對象變成AndCriteria/OrCriteria!

所以現在我們可以用& &和||來表達我們的標準表達式。我們習慣的語法。

repository.FindAll(Customer.Columns.Age == 20 && Customer.Columns.Name == 「foo」); 

repository.FindAll(Customer.Columns.FirstName == 「Foo」 || Customer.Columns.LastName == 「Bar」); 

相關的操作員重載如下所示。

public static bool operator true(Criteria<T> criteria) { 
    return false; 
} 

public static bool operator false(Criteria<T> criteria) { 
    return false; 
} 

public static Criteria<T> operator &(Criteria<T> lhs, Criteria<T> rhs) { 
    return new AndCriteria<T>(lhs, rhs); 
} 

public static Criteria<T> operator |(Criteria<T> lhs, Criteria<T> rhs) { 
    return new OrCriteria<T>(lhs, rhs); 
} 
+0

感謝您的工作鏈接。事實證明,這篇文章並沒有真正回答我的問題。或者如果是這樣,我沒有得到它。 – comecme

1

從微軟(http://msdn.microsoft.com/en-us/library/6292hy1k.aspx):

此前C#2.0,使用真假運營商創建與類型(如SqlBool)兼容的可爲空的值類型的用戶定義的 。然而, 語言現在提供內置的空值類型的支持,並 你應該儘可能的使用,而不是那些超載的真實, 假運營商。

如果您只想評估您的對象爲布爾值,請刪除運算符true和運算符false重載,然後使用bool重載。

+0

我沒有看到我的真假過載邏輯會出現什麼問題。如果'_i <= 0',false將返回true,因爲小於或等於零的值被視爲假值。 – comecme

+0

你說得對,因爲我可以刪除'true'和'false'運算符,並將隱式類型轉換爲'bool'。但是這留下了我的另一個問題沒有答案:什麼時候可以有用? – comecme

+0

**我不明白什麼是邏輯錯誤**你是對的,我的不好。 **什麼時候可以有用?**好,取決於你想要做的事情。如果你只是想評估你的對象布爾值,那麼布爾超載就是你所需要的。它們的聲音已經過時了,至少是爲了它們的主要目的(創建可爲空的類型)。正如其他人發佈的那樣,它們也可以顯式地用於製作LINQ邏輯AND和OR的簡寫符號。 –

1

回答你最後一個問題:「我怎樣才能讓我的類型能夠檢查兩個變量是否都是真的? - 只需使用&運算符。 &&的整點是短路,以便在不必要時不檢查第二個參數。

檢查了這一點:

Console.WriteLine(b1 & b2); // outputs 1 
Console.WriteLine(b2 & b1); // outputs 1 

你實際上是缺失的,這將允許您使用MYSTRUCT(與&|)作爲布爾一個重要的一點 - 一個隱式轉換爲bool

public static implicit operator bool(MyStruct ms) { 
    return ms._i > 0; 
} 

這允許您使用MyStruct(因此也是運營商的結果):

if (b1 & b2) 
    Console.WriteLine("foo"); 

隨着最後,可能是最重要的,注意:在你的榜樣的問題來自於你想要做的邏輯運算(檢查MyStruct 2個實例是否true)的事實,但你的&運營商錯誤地實施了這樣的目的。它在二進制算術方面起作用,當用參數MyStruct(1)true)和MyStruct(-1)false)調用時產生MyStruct的值爲1的實例。所以它基本上是(true & false) == true。這就是爲什麼b1 && b2給出與您的示例中的b2 && b1不同的結果。基於該操作員的任何其他邏輯將被破壞且不可預知。在false&中以.NET實現的&&的行爲證實了這一點。

編輯:你想能夠使用MyStruct作爲布爾值。您可以實現運營商truefalse並期望&&||在布爾邏輯方面的工作。然而,你(使用&int場),這使得該實現的&與你期望的布爾邏輯((1 & -1) == 1,這意味着(true & false) == false在你的MyStruct布爾值的解釋)不兼容實現二進制算術方面&。現在,考慮&&一般不是邏輯運算符(它不返回bool) - 它是作爲T.false(x) ? x : T.&(x, y)實現短路。請注意,在您的情況下,它將返回MyStruct,根據其字段的值,您將其解釋爲truefalse。底線:你期望&&做一個邏輯測試兩個操作數,但&&的.NET實現使用你的實現&,這是不符合你期望的布爾邏輯兼容。

+1

我不需要實現隱式轉換爲'bool'來使用'if(b1&b2)'。它只是對'b1&b2'的結果執行'true'運算符。實現重載時唯一的區別是'Console.WriteLine(b1 && b2)'不打印'1'或'-1',但實際上是'True'或'False'。如果我執行'bool' cast並移除'&'運算符,那麼只會使用'bool'。在這種情況下,我可以刪除'true'和'false'重載,導致它們不會再被執行。 – comecme

+1

你說得對,我的壞,我沒有測試。你也是對的,如果'bool'被實現,'&','true'和'false'可以被刪除(在這個特定情況下)。我猜這就是你實際需要的,因爲'MyStruct'的行爲在邏輯上是正確的。所以你尋求'false'的有用實現繼續;-) –

0

真/假運算符的點是提供布爾邏輯語義而不需要隱式轉換到bool

如果你讓你的類型隱含轉換成bool,不再需要真/假運營商。但是,如果你只想要顯式轉換,或沒有轉換,但仍希望讓你的類型,如ifwhile expresssion一個條件,你可以使用truefalse運營商。

相關問題