C # 'adalah' kinerja operator

102

Saya memiliki program yang membutuhkan kinerja cepat. Dalam salah satu loop dalamnya, saya perlu menguji jenis objek untuk melihat apakah itu mewarisi dari antarmuka tertentu.

Salah satu cara untuk melakukannya adalah dengan fungsionalitas pemeriksaan tipe built-in CLR. Metode paling elegan yang mungkin ada adalah kata kunci 'is':

if (obj is ISpecialType)

Pendekatan lain adalah memberikan kelas dasar fungsi GetType () virtual saya sendiri yang mengembalikan nilai enum yang telah ditentukan sebelumnya (dalam kasus saya, sebenarnya, saya hanya perlu bool). Metode itu akan cepat, tetapi kurang elegan.

Saya telah mendengar bahwa ada instruksi IL khusus untuk kata kunci 'is', tetapi itu tidak berarti itu dijalankan dengan cepat ketika diterjemahkan ke dalam perakitan asli. Adakah yang bisa berbagi beberapa wawasan tentang kinerja 'adalah' versus metode lainnya?

UPDATE: Terima kasih atas semua jawaban yang diinformasikan! Tampaknya beberapa poin berguna tersebar di antara jawaban: Poin Andrew tentang 'adalah' secara otomatis melakukan pemeran itu penting, tetapi data kinerja yang dikumpulkan oleh Binary Worrier dan Ian juga sangat berguna. Alangkah baiknya jika salah satu jawaban diedit untuk menyertakan semua informasi ini.

JubJub
sumber
2
btw, CLR tidak akan memberi Anda kemungkinan untuk membuat fungsi Type GetType () Anda sendiri, karena ini melanggar salah satu aturan utama CLR - benar-benar tipe
abatishchev
1
Eh, saya tidak sepenuhnya yakin apa yang Anda maksud dengan aturan "benar-benar jenis", tetapi saya memahami bahwa CLR memiliki fungsi Tipe GetType () bawaan. Jika saya menggunakan metode itu, itu akan dengan fungsi dari nama yang berbeda mengembalikan beberapa enum, jadi tidak akan ada konflik nama / simbol.
JubJub
3
Saya pikir abatishchev berarti "keamanan tipe". GetType () bersifat non-virtual untuk mencegah suatu tipe berbohong tentang dirinya sendiri dan karena itu menjaga keamanan tipe.
Andrew Hare
2
Sudahkah Anda mempertimbangkan untuk mengambil dan menyimpan dalam cache kepatuhan jenis sehingga Anda tidak perlu melakukannya dalam loop? Tampaknya setiap pertanyaan kinerja selalu diberi +1 secara besar-besaran tetapi bagi saya ini sepertinya pemahaman yang buruk tentang c #. Apakah sebenarnya terlalu lambat? Bagaimana? Apa yang sudah kamu coba? Jelas tidak banyak memberikan komentar Anda atas jawaban ...
Gusdor

Jawaban:

114

Penggunaan isdapat mengganggu kinerja jika, setelah Anda memeriksa jenisnya, Anda mentransmisikan ke jenis itu. issebenarnya mentransmisikan objek ke jenis yang Anda periksa sehingga setiap pengecoran berikutnya berlebihan.

Jika Anda tetap akan melakukan cast, berikut ini pendekatan yang lebih baik:

ISpecialType t = obj as ISpecialType;

if (t != null)
{
    // use t here
}
Andrew Hare
sumber
1
Terima kasih. Tetapi jika saya tidak akan mentransmisikan objek jika kondisional gagal, apakah saya lebih baik menggunakan fungsi virtual untuk menguji jenisnya?
JubJub
4
@JubJub: tidak. Gagal aspada dasarnya melakukan operasi yang sama seperti is(yaitu, pemeriksaan tipe). Satu-satunya perbedaan adalah bahwa ia kembali, nullbukan false.
Konrad Rudolph
74

Saya dengan Ian , Anda mungkin tidak ingin melakukan ini.

Namun, asal tahu saja, ada sangat sedikit perbedaan antara keduanya, lebih dari 10.000.000 iterasi

  • Pemeriksaan enum masuk pada 700 milidetik (perkiraan)
  • Pemeriksaan IS masuk pada 1000 milidetik (perkiraan)

Saya pribadi tidak akan memperbaiki masalah ini dengan cara ini, tetapi jika saya terpaksa memilih satu metode, itu akan menjadi pemeriksaan IS bawaan, perbedaan kinerja tidak layak mempertimbangkan overhead pengkodean.

Kelas dasar dan turunan saya

class MyBaseClass
{
    public enum ClassTypeEnum { A, B }
    public ClassTypeEnum ClassType { get; protected set; }
}

class MyClassA : MyBaseClass
{
    public MyClassA()
    {
        ClassType = MyBaseClass.ClassTypeEnum.A;
    }
}
class MyClassB : MyBaseClass
{
    public MyClassB()
    {
        ClassType = MyBaseClass.ClassTypeEnum.B;
    }
}

JubJub: Seperti yang diminta info lebih lanjut tentang tes.

Saya menjalankan kedua pengujian dari aplikasi konsol (build debug) setiap pengujian terlihat seperti berikut

static void IsTest()
{
    DateTime start = DateTime.Now;
    for (int i = 0; i < 10000000; i++)
    {
        MyBaseClass a;
        if (i % 2 == 0)
            a = new MyClassA();
        else
            a = new MyClassB();
        bool b = a is MyClassB;
    }
    DateTime end = DateTime.Now;
    Console.WriteLine("Is test {0} miliseconds", (end - start).TotalMilliseconds);
}

Berjalan dalam rilis, saya mendapatkan perbedaan 60 - 70 ms, seperti Ian.

Pembaruan Lebih Lanjut - 25 Oktober 2012
Setelah beberapa tahun saya melihat sesuatu tentang ini, kompilator dapat memilih untuk menghilangkan bool b = a is MyClassBdalam rilis karena b tidak digunakan dimanapun.

Kode ini. . .

public static void IsTest()
{
    long total = 0;
    var a = new MyClassA();
    var b = new MyClassB();
    var sw = new Stopwatch();
    sw.Start();
    for (int i = 0; i < 10000000; i++)
    {
        MyBaseClass baseRef;
        if (i % 2 == 0)
            baseRef = a;//new MyClassA();
        else
            baseRef = b;// new MyClassB();
        //bool bo = baseRef is MyClassB;
        bool bo = baseRef.ClassType == MyBaseClass.ClassTypeEnum.B;
        if (bo) total += 1;
    }
    sw.Stop();
    Console.WriteLine("Is test {0} miliseconds {1}", sw.ElapsedMilliseconds, total);
}

. . . secara konsisten menunjukkanis cek masuk pada kira-kira 57 milidetik, dan perbandingan enum masuk pada 29 milidetik.

NB Saya masih lebih suka iscek, perbedaannya terlalu kecil untuk diperhatikan

Biner Worrier
sumber
35
1 untuk benar-benar menguji kinerja, alih-alih berasumsi.
Jon Tackabury
3
Jauh lebih baik untuk melakukan pengujian dengan kelas Stopwatch, daripada DateTime. Sekarang yang sangat mahal
abatishchev
2
Saya akan mempertimbangkannya, namun dalam hal ini saya tidak berpikir itu akan mempengaruhi hasilnya. Terima kasih :)
Binary Worrier
11
@Binary Worrier- Alokasi kelas operator baru Anda akan sepenuhnya menutupi perbedaan kinerja apa pun dalam operasi 'ada'. Mengapa Anda tidak menghapus operasi baru tersebut, dengan menggunakan kembali dua contoh berbeda yang telah dialokasikan sebelumnya, lalu menjalankan kembali kode dan memposting hasil Anda.
1
@mcmillab: Saya akan menjamin bahwa apa pun yang Anda lakukan, Anda akan mengalami kemacetan banyak kali lipat lebih besar daripada penurunan kinerja apa pun yang disebabkan oleh isoperator, dan bahwa terlalu banyak mendengar tentang perancangan & pengkodean di sekitar isoperator akan menghabiskan banyak uang kualitas kode dan pada akhirnya akan menjadi kinerja yang merugikan diri sendiri juga. Dalam hal ini saya mendukung pernyataan saya. The 'adalah' operator tidak akan menjadi yang masalah dengan kinerja runtime Anda.
Binary Worrier
23

Oke, jadi saya mengobrol tentang ini dengan seseorang dan memutuskan untuk menguji ini lebih lanjut. Sejauh yang saya tahu, kinerja asdan iskeduanya sangat baik, dibandingkan dengan menguji anggota Anda sendiri atau fungsi untuk menyimpan informasi tipe.

Saya menggunakan Stopwatch, yang baru saja saya pelajari mungkin bukan pendekatan yang paling dapat diandalkan, jadi saya juga mencoba UtcNow. Kemudian, saya juga mencoba pendekatan waktu Prosesor yang tampaknya mirip dengan UtcNowmenyertakan waktu pembuatan yang tidak dapat diprediksi. Saya juga mencoba membuat kelas dasar non-abstrak tanpa virtual tetapi tampaknya tidak memiliki efek yang signifikan.

Saya menjalankan ini pada Quad Q6600 dengan RAM 16GB. Bahkan dengan iterasi 50mil, angkanya masih memantul sekitar +/- 50 atau lebih milidetik jadi saya tidak akan terlalu banyak membaca perbedaan kecil.

Menarik untuk melihat bahwa x64 dibuat lebih cepat tetapi dieksekusi karena / lebih lambat dari x86

Mode Rilis x64:
Stopwatch:
As: 561ms
Is: 597ms
Properti dasar: 539ms
Bidang dasar: 555ms
Bidang RO Basis: 552ms Tes
Virtual GetEnumType (): 556ms Tes
Virtual IsB (): 588ms
Buat Waktu: 10416ms

UtcNow:
As: 499ms
Is: 532ms
Properti dasar: 479ms
Bidang dasar: 502ms
Bidang RO dasar: 491ms
Virtual GetEnumType (): 502ms
Virtual bool IsB (): 522ms
Buat Waktu: 285ms (Angka ini tampaknya tidak dapat diandalkan dengan UtcNow. Saya juga mendapatkan 109ms dan 806ms.)

Mode Rilis x86:
Stopwatch:
As: 391ms
Is: 423ms
Properti dasar: 369ms
Bidang dasar: 321ms
Bidang RO Basis: 339ms Tes
Virtual GetEnumType (): 361ms Tes
Virtual IsB (): 365ms
Buat Waktu: 14106ms

UtcNow:
As: 348ms
Is: 375ms
Properti dasar: 329ms
Bidang dasar: 286ms
Bidang RO dasar: 309ms
Virtual GetEnumType (): 321ms
Virtual bool IsB (): 332ms
Buat Waktu: 544ms (Angka ini tampaknya tidak dapat diandalkan dengan UtcNow.)

Inilah sebagian besar kodenya:

    static readonly int iterations = 50000000;
    void IsTest()
    {
        Process.GetCurrentProcess().ProcessorAffinity = (IntPtr)1;
        MyBaseClass[] bases = new MyBaseClass[iterations];
        bool[] results1 = new bool[iterations];

        Stopwatch createTime = new Stopwatch();
        createTime.Start();
        DateTime createStart = DateTime.UtcNow;
        for (int i = 0; i < iterations; i++)
        {
            if (i % 2 == 0) bases[i] = new MyClassA();
            else bases[i] = new MyClassB();
        }
        DateTime createStop = DateTime.UtcNow;
        createTime.Stop();


        Stopwatch isTimer = new Stopwatch();
        isTimer.Start();
        DateTime isStart = DateTime.UtcNow;
        for (int i = 0; i < iterations; i++)
        {
            results1[i] =  bases[i] is MyClassB;
        }
        DateTime isStop = DateTime.UtcNow; 
        isTimer.Stop();
        CheckResults(ref  results1);

        Stopwatch asTimer = new Stopwatch();
        asTimer.Start();
        DateTime asStart = DateTime.UtcNow;
        for (int i = 0; i < iterations; i++)
        {
            results1[i] = bases[i] as MyClassB != null;
        }
        DateTime asStop = DateTime.UtcNow; 
        asTimer.Stop();
        CheckResults(ref  results1);

        Stopwatch baseMemberTime = new Stopwatch();
        baseMemberTime.Start();
        DateTime baseStart = DateTime.UtcNow;
        for (int i = 0; i < iterations; i++)
        {
            results1[i] = bases[i].ClassType == MyBaseClass.ClassTypeEnum.B;
        }
        DateTime baseStop = DateTime.UtcNow;
        baseMemberTime.Stop();
        CheckResults(ref  results1);

        Stopwatch baseFieldTime = new Stopwatch();
        baseFieldTime.Start();
        DateTime baseFieldStart = DateTime.UtcNow;
        for (int i = 0; i < iterations; i++)
        {
            results1[i] = bases[i].ClassTypeField == MyBaseClass.ClassTypeEnum.B;
        }
        DateTime baseFieldStop = DateTime.UtcNow;
        baseFieldTime.Stop();
        CheckResults(ref  results1);


        Stopwatch baseROFieldTime = new Stopwatch();
        baseROFieldTime.Start();
        DateTime baseROFieldStart = DateTime.UtcNow;
        for (int i = 0; i < iterations; i++)
        {
            results1[i] = bases[i].ClassTypeField == MyBaseClass.ClassTypeEnum.B;
        }
        DateTime baseROFieldStop = DateTime.UtcNow;
        baseROFieldTime.Stop();
        CheckResults(ref  results1);

        Stopwatch virtMethTime = new Stopwatch();
        virtMethTime.Start();
        DateTime virtStart = DateTime.UtcNow;
        for (int i = 0; i < iterations; i++)
        {
            results1[i] = bases[i].GetClassType() == MyBaseClass.ClassTypeEnum.B;
        }
        DateTime virtStop = DateTime.UtcNow;
        virtMethTime.Stop();
        CheckResults(ref  results1);

        Stopwatch virtMethBoolTime = new Stopwatch();
        virtMethBoolTime.Start();
        DateTime virtBoolStart = DateTime.UtcNow;
        for (int i = 0; i < iterations; i++)
        {
            results1[i] = bases[i].IsB();
        }
        DateTime virtBoolStop = DateTime.UtcNow;
        virtMethBoolTime.Stop();
        CheckResults(ref  results1);


        asdf.Text +=
        "Stopwatch: " + Environment.NewLine 
          +   "As:  " + asTimer.ElapsedMilliseconds + "ms" + Environment.NewLine
           +"Is:  " + isTimer.ElapsedMilliseconds + "ms" + Environment.NewLine
           + "Base property:  " + baseMemberTime.ElapsedMilliseconds + "ms" + Environment.NewLine + "Base field:  " + baseFieldTime.ElapsedMilliseconds + "ms" + Environment.NewLine + "Base RO field:  " + baseROFieldTime.ElapsedMilliseconds + "ms" + Environment.NewLine + "Virtual GetEnumType() test:  " + virtMethTime.ElapsedMilliseconds + "ms" + Environment.NewLine + "Virtual IsB() test:  " + virtMethBoolTime.ElapsedMilliseconds + "ms" + Environment.NewLine + "Create Time :  " + createTime.ElapsedMilliseconds + "ms" + Environment.NewLine + Environment.NewLine+"UtcNow: " + Environment.NewLine + "As:  " + (asStop - asStart).Milliseconds + "ms" + Environment.NewLine + "Is:  " + (isStop - isStart).Milliseconds + "ms" + Environment.NewLine + "Base property:  " + (baseStop - baseStart).Milliseconds + "ms" + Environment.NewLine + "Base field:  " + (baseFieldStop - baseFieldStart).Milliseconds + "ms" + Environment.NewLine + "Base RO field:  " + (baseROFieldStop - baseROFieldStart).Milliseconds + "ms" + Environment.NewLine + "Virtual GetEnumType():  " + (virtStop - virtStart).Milliseconds + "ms" + Environment.NewLine + "Virtual bool IsB():  " + (virtBoolStop - virtBoolStart).Milliseconds + "ms" + Environment.NewLine + "Create Time :  " + (createStop-createStart).Milliseconds + "ms" + Environment.NewLine;
    }
}

abstract class MyBaseClass
{
    public enum ClassTypeEnum { A, B }
    public ClassTypeEnum ClassType { get; protected set; }
    public ClassTypeEnum ClassTypeField;
    public readonly ClassTypeEnum ClassTypeReadonlyField;
    public abstract ClassTypeEnum GetClassType();
    public abstract bool IsB();
    protected MyBaseClass(ClassTypeEnum kind)
    {
        ClassTypeReadonlyField = kind;
    }
}

class MyClassA : MyBaseClass
{
    public override bool IsB() { return false; }
    public override ClassTypeEnum GetClassType() { return ClassTypeEnum.A; }
    public MyClassA() : base(MyBaseClass.ClassTypeEnum.A)
    {
        ClassType = MyBaseClass.ClassTypeEnum.A;
        ClassTypeField = MyBaseClass.ClassTypeEnum.A;            
    }
}
class MyClassB : MyBaseClass
{
    public override bool IsB() { return true; }
    public override ClassTypeEnum GetClassType() { return ClassTypeEnum.B; }
    public MyClassB() : base(MyBaseClass.ClassTypeEnum.B)
    {
        ClassType = MyBaseClass.ClassTypeEnum.B;
        ClassTypeField = MyBaseClass.ClassTypeEnum.B;
    }
}
Jared Thirsk
sumber
45
(Beberapa bonus 5 Shakespeare yang terinspirasi ...) Menjadi, atau tidak menjadi: itulah pertanyaannya: Apakah lebih mulia dalam kode menderita Pencacahan dan sifat dasar abstrak, Atau menerima tawaran perantara ahli bahasa Dan dengan menjalankan instruksinya, percaya mereka? Untuk menebak: bertanya-tanya; Tidak lagi; dan dengan waktu untuk membedakan, kita mengakhiri sakit kepala dan ribuan keajaiban bawah sadar yang diwariskan oleh pembuat kode terikat waktu. Ini adalah penutup yang benar-benar diharapkan. Untuk mati, tidak, tapi tidur; Ya, saya akan tidur, kemungkinan untuk diimpikan adalah dan seperti apa yang mungkin diturunkan dari kelas paling dasar.
Jared Thirsk
Bisakah kita menyimpulkan dari sini bahwa mengakses properti lebih cepat di x64 daripada mengakses bidang !!! Karena itu sangat mengejutkan saya bagaimana ini bisa terjadi?
Didier A.
1
Saya tidak akan menyimpulkan itu, karena: "Bahkan dengan pengulangan 50mil, angkanya masih memantul sekitar +/- 50 atau lebih milidetik jadi saya tidak akan membaca terlalu banyak tentang perbedaan kecil."
Jared Thirsk
16

Andrew benar. Faktanya dengan analisis kode ini dilaporkan oleh Visual Studio sebagai pemeran yang tidak perlu.

Satu gagasan (tanpa mengetahui apa yang Anda lakukan adalah sedikit bidikan dalam kegelapan), tetapi saya selalu disarankan untuk menghindari pemeriksaan seperti ini, dan sebaliknya memiliki kelas lain. Jadi, daripada melakukan beberapa pemeriksaan dan melakukan tindakan yang berbeda tergantung pada jenisnya, buat kelas tahu cara memprosesnya sendiri ...

misalnya Obj bisa ISpecialType atau IType;

keduanya memiliki metode DoStuff () yang ditentukan. Untuk IType bisa saja mengembalikan atau mengerjakan custom, sedangkan ISpecialType bisa melakukan hal lain.

Tindakan ini kemudian akan sepenuhnya menghapus transmisi apa pun, membuat kode lebih bersih dan lebih mudah dikelola, dan kelas tahu cara melakukan tugasnya sendiri.

Ian
sumber
Ya, karena semua yang akan saya lakukan jika tes tipe benar adalah memanggil metode antarmuka tertentu di atasnya, saya bisa memindahkan metode antarmuka itu ke kelas dasar dan membuatnya tidak melakukan apa-apa secara default. Itu mungkin lebih elegan daripada membuat fungsi virtual untuk menguji tipe.
JubJub
Saya melakukan tes serupa dengan Binary Worrier setelah komentar abatishchev dan menemukan hanya selisih 60ms lebih dari 10.000.000 itterasi.
Ian
1
Wow, terima kasih atas bantuannya. Saya kira saya akan tetap menggunakan operator pemeriksaan tipe untuk saat ini, kecuali tampaknya tepat untuk mengatur ulang struktur kelas. Saya akan menggunakan operator 'sebagai' seperti yang disarankan Andrew karena saya tidak ingin melakukan cast secara berlebihan.
JubJub
15

Saya melakukan perbandingan kinerja pada dua kemungkinan perbandingan tipe

  1. myobject.GetType () == typeof (MyClass)
  2. myobject adalah MyClass

Hasilnya adalah: Menggunakan "is" 10x lebih cepat !!!

Keluaran:

Waktu untuk Jenis-Perbandingan: 00: 00: 00.456

Waktu untuk Perbandingan-Is: 00: 00: 00.042

Kode Saya:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;

namespace ConsoleApplication3
{
    class MyClass
    {
        double foo = 1.23;
    }

    class Program
    {
        static void Main(string[] args)
        {
            MyClass myobj = new MyClass();
            int n = 10000000;

            Stopwatch sw = Stopwatch.StartNew();

            for (int i = 0; i < n; i++)
            {
                bool b = myobj.GetType() == typeof(MyClass);
            }

            sw.Stop();
            Console.WriteLine("Time for Type-Comparison: " + GetElapsedString(sw));

            sw = Stopwatch.StartNew();

            for (int i = 0; i < n; i++)
            {
                bool b = myobj is MyClass;
            }

            sw.Stop();
            Console.WriteLine("Time for Is-Comparison: " + GetElapsedString(sw));
        }

        public static string GetElapsedString(Stopwatch sw)
        {
            TimeSpan ts = sw.Elapsed;
            return String.Format("{0:00}:{1:00}:{2:00}.{3:000}", ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds);
        }
    }
}
Knasterbax
sumber
13

Poin yang dibuat Andrew Hare tentang kinerja yang hilang ketika Anda melakukan ispemeriksaan dan kemudian pemeran valid tetapi di C # 7.0 yang dapat kita lakukan adalah memeriksa kecocokan pola penyihir untuk menghindari pemeran tambahan nanti:

if (obj is ISpecialType st)
{
   //st is in scope here and can be used
}

Lebih jauh lagi jika Anda perlu memeriksa antara beberapa tipe konstruksi pencocokan pola C # 7.0 sekarang memungkinkan Anda untuk melakukan switchpada tipe:

public static double ComputeAreaModernSwitch(object shape)
{
    switch (shape)
    {
        case Square s:
            return s.Side * s.Side;
        case Circle c:
            return c.Radius * c.Radius * Math.PI;
        case Rectangle r:
            return r.Height * r.Length;
        default:
            throw new ArgumentException(
                message: "shape is not a recognized shape",
                paramName: nameof(shape));
    }
}

Anda dapat membaca lebih lanjut tentang pencocokan pola di C # dalam dokumentasi di sini .

Krzysztof Branicki
sumber
1
Solusi yang valid, pasti, tetapi fitur pencocokan pola C # ini membuat saya sedih, ketika mendorong kode "iri fitur" seperti ini. Tentunya kita harus berjuang untuk enkapsulasi logika di mana hanya objek turunan yang "tahu" bagaimana menghitung luas mereka sendiri, dan kemudian mereka hanya mengembalikan nilainya?
Dib
2
SO membutuhkan tombol filter (pada pertanyaan) untuk jawaban yang berlaku untuk versi yang lebih baru dari kerangka kerja, platform dll. Jawaban ini membentuk dasar yang benar untuk C # 7.
Nick Westgate
1
@Dib OOP ideal dilempar keluar dari jendela saat Anda bekerja dengan jenis / kelas / antarmuka yang tidak Anda kontrol. Pendekatan ini juga berguna ketika menangani hasil dari suatu fungsi yang dapat mengembalikan satu dari banyak nilai dari tipe yang benar-benar berbeda (karena C # masih belum mendukung tipe-gabungan - Anda dapat menggunakan pustaka seperti itu OneOf<T...>tetapi mereka memiliki kekurangan utama) .
Dai
5

Jika ada yang bertanya-tanya, saya telah melakukan pengujian di Unity engine 2017.1, dengan skrip versi runtime .NET4.6 (Experimantal) pada notebook dengan CPU i5-4200U. Hasil:

Average Relative To Local Call LocalCall 117.33 1.00 is 241.67 2.06 Enum 139.33 1.19 VCall 294.33 2.51 GetType 276.00 2.35

Artikel lengkap: http://www.ennoble-studios.com/tuts/unity-c-performance-comparison-is-vs-enum-vs-virtual-call.html

Gru
sumber
Tautan artikel sudah mati.
James Wilkins
Tautan @James dihidupkan kembali.
Gru
Hal-hal bagus - tetapi saya tidak memberi suara negatif kepada Anda (sebenarnya saya memberikan suara positif); Jika Anda bertanya-tanya. :)
James Wilkins
-3

Saya selalu disarankan untuk menghindari pemeriksaan seperti ini, dan sebaliknya memiliki kelas lain. Jadi, daripada melakukan beberapa pemeriksaan dan melakukan tindakan yang berbeda tergantung pada jenisnya, buat kelas tahu cara memprosesnya sendiri ...

misalnya Obj bisa ISpecialType atau IType;

keduanya memiliki metode DoStuff () yang ditentukan. Untuk IType bisa saja mengembalikan atau mengerjakan custom, sedangkan ISpecialType bisa melakukan hal lain.

Tindakan ini kemudian akan sepenuhnya menghapus transmisi apa pun, membuat kode lebih bersih dan lebih mudah dikelola, dan kelas tahu cara melakukan tugasnya sendiri.

pengguna3802787
sumber
1
Ini tidak menjawab pertanyaan itu. Bagaimanapun, kelas mungkin tidak selalu tahu bagaimana memproses diri mereka sendiri karena kurangnya konteks. Kami menerapkan logika serupa untuk penanganan pengecualian saat kami mengizinkan pengecualian untuk naik ke rantai panggilan sampai beberapa metode / fungsi memiliki konteks yang cukup untuk menangani kesalahan.
Vakhtang