Untuk apa operator palsu di C #?

107

Ada dua operator aneh di C #:

Jika saya memahami hak ini, operator ini dapat digunakan dalam tipe yang ingin saya gunakan sebagai pengganti ekspresi boolean dan di mana saya tidak ingin memberikan konversi implisit ke bool.

Katakanlah saya memiliki kelas berikut:

    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;
        }

    }

Jadi saya bisa menulis kode berikut:

    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)

Namun untuk semua contoh di atas, hanya operator yang benar yang dijalankan. Jadi, untuk apa operator palsu di C #?

Catatan: Contoh lainnya dapat ditemukan di sini , di sini dan di sini .

Jakub Šturc
sumber
Dokumen modern dapat ditemukan di docs.microsoft.com/en-us/dotnet/csharp/language-reference/… . Dokumen menyarankan bahwa tidak ada alasan untuk mendefinisikan operator ini lagi karena C # 2.0 menambahkan tipe nullable.
Mark Amery

Jawaban:

65

Anda dapat menggunakannya untuk mengganti operator &&dan ||.

The &&dan ||operator tidak bisa ditimpa, tetapi jika Anda menimpa |, &, truedan falsedengan cara yang persis tepat compiler akan memanggil |dan &ketika Anda menulis ||dan &&.

Misalnya, lihat kode ini (dari http://ayende.com/blog/1574/nhibernate-criteria-api-operator-overloading - tempat saya mengetahui tentang trik ini; versi arsip oleh @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;
}

Ini jelas merupakan efek samping dan bukan seperti yang dimaksudkan untuk digunakan, tetapi berguna.

Nir
sumber
tautan Anda adalah 404. Tidak yakin bagaimana Anda ingin mengedit ini, jadi saya biarkan saja.
user7116
Saya memperbarui URL dengan salinan arsip sehingga masih bisa dibaca.
IAmTimCorey
25

Shog9 dan Nir: terima kasih atas jawaban Anda. Jawaban itu mengarahkan saya ke artikel Steve Eichert dan itu mengarahkan saya ke msdn :

Operasi x && y dievaluasi sebagai T. salah (x)? x: T. & (x, y), di mana T.false (x) adalah pemanggilan dari operator yang salah dideklarasikan di T, dan T. & (x, y) adalah pemanggilan operator yang dipilih &. Dengan kata lain, x dievaluasi pertama kali dan operator salah dipanggil pada hasil untuk menentukan apakah x pasti salah. Kemudian, jika x pasti salah, hasil operasi adalah nilai yang sebelumnya dihitung untuk x. Jika tidak, y dievaluasi, dan operator yang dipilih & dipanggil pada nilai yang sebelumnya dihitung untuk x dan nilai yang dihitung untuk y untuk menghasilkan hasil operasi.

Jakub Šturc
sumber
Saya bertanya-tanya mengapa mereka tidak memilih untuk menggunakan (!T.true(x)) ? x : T.&(x, y)logika sebagai gantinya.
Des Nerger
14

Halaman yang Anda tautkan ke http://msdn.microsoft.com/en-us/library/6x6y6z4d.aspx mengatakan untuk apa mereka, yang merupakan cara menangani masalah nullable sebelum jenis nilai nullable diperkenalkan.

Saya kira saat ini mereka bagus untuk hal-hal yang sama seperti ArrayList - sama sekali tidak ada.

Will Dean
sumber
7

AFAIK, itu akan digunakan dalam tes palsu, seperti saat &&operator ikut bermain. Ingat, && short-circuit, jadi dalam ekspresi

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

mFalse.false()dipanggil, dan setelah mengembalikan trueekspresi dikurangi menjadi panggilan ke 'mFalse.true ()' (yang kemudian harus kembali false, atau hal-hal akan menjadi aneh).

Perhatikan bahwa Anda harus mengimplementasikan &operator agar ekspresi tersebut dapat dikompilasi, karena ini digunakan jika mFalse.false()kembali false.

Shog9
sumber
3

Tampaknya dari artikel MSDN yang Anda tautkan, disediakan untuk memungkinkan tipe boolean nullable sebelum tipe Nullable (yaitu int ?, bool ?, dll.) Diperkenalkan ke dalam bahasa di C # 2. Jadi, Anda akan menyimpan nilai internal yang menunjukkan apakah nilai itu benar atau salah atau nol, yaitu dalam contoh Anda> 0 untuk benar, <0 untuk salah dan == 0 untuk nol, dan kemudian Anda akan mendapatkan semantik nol gaya SQL. Anda juga harus mengimplementasikan metode atau properti .IsNull agar nullity dapat diperiksa secara eksplisit.

Dibandingkan dengan SQL, bayangkan Tabel tabel dengan 3 baris dengan nilai Foo disetel ke true, 3 baris dengan nilai Foo disetel ke salah dan 3 baris dengan nilai Foo disetel ke null.

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

Untuk menghitung semua baris, Anda harus melakukan hal berikut: -

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

Sintaks 'IS NULL' ini akan memiliki kode yang setara di kelas Anda sebagai .IsNull ().

LINQ membuat perbandingan ke C # lebih jelas: -

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

Bayangkan MyTypeEnumberable memiliki konten database yang sama persis, yaitu 3 nilai sama dengan true, 3 nilai sama dengan false dan 3 nilai sama dengan null. Dalam kasus ini totalCount akan bernilai 6 dalam kasus ini. Namun, jika kami menulis ulang kode sebagai: -

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

Kemudian totalCount akan bernilai 9.

Contoh DBNull yang diberikan dalam artikel MSDN tertaut di operator palsu menunjukkan kelas di BCL yang memiliki perilaku yang tepat ini.

Akibatnya kesimpulannya adalah Anda tidak boleh menggunakan ini kecuali Anda benar-benar yakin Anda menginginkan jenis perilaku ini, lebih baik menggunakan sintaks nullable yang jauh lebih sederhana !!

Pembaruan: Saya baru saja memperhatikan Anda perlu mengganti operator logika secara manual!, || dan && untuk membuatnya berfungsi dengan baik. Saya percaya operator palsu memasukkan ke operator logis ini, yaitu menunjukkan kebenaran, kepalsuan atau 'sebaliknya'. Seperti dicatat dalam komentar lain! X tidak akan berhasil; Anda harus membebani!. Keanehan!

ljs
sumber