C # 'operatör performansıdır'


103

Hızlı performans gerektiren bir programım var. İç döngülerinden birinde, belirli bir arayüzden miras alıp almadığını görmek için bir nesnenin türünü test etmem gerekiyor.

Bunu yapmanın bir yolu, CLR'nin yerleşik tür kontrol işlevi olabilir. Muhtemelen 'is' anahtar kelimesi olmanın en zarif yöntemi:

if (obj is ISpecialType)

Diğer bir yaklaşım, temel sınıfa, önceden tanımlanmış bir enum değeri döndüren kendi sanal GetType () işlevimi vermektir (benim durumumda, aslında, sadece bir bool'a ihtiyacım var). Bu yöntem hızlı ama daha az zarif olacaktır.

Özellikle 'is' anahtar kelimesi için bir IL talimatı olduğunu duydum, ancak bu, yerel derlemeye çevrildiğinde hızlı yürütüldüğü anlamına gelmez. Diğer yönteme karşı 'eşittir'in performansı hakkında bir fikir paylaşan var mı?

GÜNCELLEME: Bilgilendirilmiş tüm cevaplar için teşekkürler! Yanıtlar arasında birkaç yardımcı nokta yayılmış gibi görünüyor: Andrew'un bir oyuncu kadrosunu otomatik olarak gerçekleştirmesi 'olduğu' ile ilgili noktası çok önemli, ancak Binary Worrier ve Ian tarafından toplanan performans verileri de son derece yararlı. Cevaplardan birinin tüm bu bilgileri içerecek şekilde düzenlenmesi harika olurdu .


2
btw, CLR size kendi Type GetType () işlevinizi yaratma imkanı vermez, çünkü ana CLR kurallarından birini - gerçekten türler
abatishchev

1
"Gerçekten türler" kuralıyla ne demek istediğinizden tam olarak emin değilim, ancak CLR'nin yerleşik bir Type GetType () işlevi olduğunu anlıyorum. Bu yöntemi kullanacak olsaydım, farklı bir isme sahip bir fonksiyonla bir numaralandırma döndürürdü, böylece herhangi bir isim / sembol çakışması olmazdı.
JubJub

3
Bence abatishchev "tip güvenlik" demek. GetType (), bir türün kendi hakkında yalan söylemesini ve dolayısıyla tür güvenliğini korumasını önlemek için sanal değildir.
Andrew Hare

2
Döngüler içinde yapmak zorunda kalmamak için tür uyumluluğunu önceden getirmeyi ve önbelleğe almayı düşündünüz mü? Görünüşe göre her mükemmel soru her zaman kitlesel olarak + 1'lendi, ancak bu bana c # konusunda yetersiz bir anlayış gibi görünüyor. Gerçekten çok mu yavaş? Nasıl? Ne denedin Açıkçası çok ... yanıtlara yorumlarınızı verilmemiştir
Gusdor

Yanıtlar:


115

isTürü kontrol ettikten sonra o türe çevirirseniz kullanmak performansa zarar verebilir. isaslında nesneyi kontrol ettiğiniz türe dönüştürür, böylece sonraki herhangi bir çevrim gereksizdir.

Yine de oyuncu seçimi yapacaksanız, işte daha iyi bir yaklaşım:

ISpecialType t = obj as ISpecialType;

if (t != null)
{
    // use t here
}

1
Teşekkürler. Ancak koşullu başarısız olursa nesneyi yayınlamayacaksam, bunun yerine türü test etmek için sanal bir işlev kullanmam daha iyi olur mu?
JubJub

4
@JubJub: hayır. Bir başarısızlık, astemelde aynı işlemi gerçekleştirir is(yani, tip kontrolü). Tek fark, bunun nullyerine geri dönmesidir false.
Konrad Rudolph

74

Ian ile birlikteyim , muhtemelen bunu yapmak istemezsin.

Ancak, bildiğiniz gibi, ikisi arasında çok az fark var, 10.000.000'den fazla yineleme

  • Numaralandırma kontrolü 700 milisaniyede (yaklaşık) gelir
  • IS kontrolü 1000 milisaniyede gelir (yaklaşık)

Şahsen bu sorunu bu şekilde çözmezdim, ancak bir yöntem seçmeye zorlanırsam, bu yerleşik IS kontrolü olur, performans farkı kodlama ek yükünü dikkate almaya değmez.

Temel ve türetilmiş sınıflarım

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: Testler hakkında daha fazla bilgi istendiği gibi.

Her iki testi de bir konsol uygulamasından (hata ayıklama yapısı) çalıştırdım, her test aşağıdaki gibi görünüyor

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

Yayınlanırken, Ian gibi 60 - 70 ms arasında bir fark elde ediyorum.

Daha Fazla Güncelleme - 25 Ekim 2012
Birkaç yıl aradan sonra bununla ilgili bir şey fark ettim, derleyici bool b = a is MyClassBb herhangi bir yerde kullanılmadığı için yayınlamayı ihmal etmeyi seçebilir .

Bu kod. . .

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

. . . sürekli olarak iskontrolün yaklaşık 57 milisaniyede geldiğini ve enum karşılaştırmasının 29 milisaniyede geldiğini gösterir.

Not: Yine de isçeki tercih ederim, aradaki fark çok küçük


35
Varsaymak yerine performansı gerçekten test etmek için +1.
Jon Tackabury

3
DateTime yerine Kronometre sınıfıyla test yapmak çok daha
iyi.Şimdi

2
Bunu dikkate alacağım, ancak bu durumda sonucu etkileyeceğini düşünmüyorum. Teşekkürler :)
Binary Worrier

11
@Binary Worrier - Sınıfların yeni operatör tahsisleri, 'is' operasyonlarındaki performans farklılıklarını tamamen gölgede bırakacak. Neden önceden ayrılmış iki farklı örneği yeniden kullanarak bu yeni işlemleri kaldırıp ardından kodu yeniden çalıştırıp sonuçlarınızı göndermiyorsunuz.

1
@mcmillab: Ne yaparsanız yapın, isoperatörün size yol açtığı herhangi bir performans düşüşünden daha büyük birçok sipariş darboğazına sahip isolacağınızı ve operatörün etrafında tasarlama ve kodlamanın aşırı duyulmasının, kod kalitesi ve sonuçta performans açısından kendi kendini yenen olacaktır. Bu durumda ifademin arkasındayım. 'İs' operatör olduğunu asla olacak sizin çalışma zamanı performansı ile sorunu.
Binary Worrier

23

Tamam, bu konuda biriyle sohbet ediyordum ve bunu daha fazla test etmeye karar verdim. Anladığım kadarıyla, tür bilgilerini depolamak için kendi üyenizi veya işlevinizi test etmeye kıyasla performansı asve isikisi de çok iyi.

StopwatchYeni öğrendiğim en güvenilir yaklaşım olmayabilir kullandım , bu yüzden denedim UtcNow. Daha sonra, UtcNowöngörülemeyen oluşturma süreleri eklemeye benzer görünen İşlemci zamanı yaklaşımını da denedim . Ayrıca temel sınıfı hiç sanal olmadan soyut hale getirmeyi denedim, ancak önemli bir etkisi olmadı.

Bunu 16GB RAM'li bir Quad Q6600'de çalıştırdım. 50 millik yinelemelerle bile, sayılar hala +/- 50 milisaniye civarında sıçrıyor, bu yüzden küçük farkları çok fazla okumazdım.

X64'ün daha hızlı oluşturulduğunu ancak x86 olarak / daha yavaş yürütüldüğünü görmek ilginçti

x64 Yayın Modu:
Kronometre:
As: 561ms
Is: 597ms
Temel özellik: 539ms
Temel alan: 555ms
Temel RO alanı: 552ms
Virtual GetEnumType () testi: 556ms
Virtual IsB () testi: 588ms
Oluşturma Süresi: 10416ms

UtcNow:
As: 499ms
Is: 532ms
Temel özellik: 479ms
Temel alan: 502ms
Temel RO alanı: 491ms
Virtual GetEnumType (): 502ms
Virtual bool IsB (): 522ms
Create Time: 285ms (Bu sayı UtcNow ile güvenilmez görünüyor. Ayrıca 109ms alıyorum ve 806ms.)

x86 Yayın Modu:
Kronometre:
As: 391ms
Is: 423ms
Temel özellik: 369ms
Temel alan: 321ms
Temel RO alanı: 339ms
Virtual GetEnumType () testi: 361ms
Virtual IsB () testi: 365ms
Oluşturma Süresi: 14106ms

UtcNow:
As: 348ms
Is: 375ms
Temel özellik: 329ms
Temel alan: 286ms
Temel RO alanı: 309ms
Virtual GetEnumType (): 321ms
Virtual bool IsB (): 332ms
Oluşturma Süresi: 544ms (Bu sayı UtcNow ile güvenilmez görünüyor.)

İşte kodun çoğu:

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

45
(Shakespeare'den esinlenen bir miktar bonus ...) Olmak ya da olmamak: soru şu: Kodda acı çekecek kadar asil mi? dilbilimci Ve onun talimatına başvurarak onlara güveniyor musunuz? Tahmin etmek için: merak etmek; Daha fazla yok; ve ayırt etmek için bir zamanlama ile baş ağrısını ve zamana bağlı kodlayıcıların mirasçısı olduğu binlerce bilinçaltı merakı sona erdiririz. "Devoutly'nin dilediği bir kapanış. Ölmek, hayır, uyumak; Evet, uyuyacağım, hayal edebileceğim bir şey ve sınıfın en temelinden türetilen şeyde olduğu gibi.
Jared Thirsk

Buradan bir mülke erişimin x64'te bir alana erişmenin daha hızlı olduğu sonucuna varabilir miyiz !!! Bunun nasıl olabileceği benim için çok büyük bir sürpriz mi?
Didier A.

1
Bu sonuca varamam, çünkü: "50mil yinelemelerde bile sayılar hala +/- 50 milisaniye civarında zıplıyor, bu yüzden küçük farkları çok fazla okumam."
Jared Thirsk

16

Andrew haklı. Aslında kod analizi ile bu, Visual Studio tarafından gereksiz bir döküm olarak bildirilir.

Bir fikir (ne yaptığınızı bilmeden karanlıkta biraz çekim yapmaktır), ama her zaman böyle kontrol etmekten kaçınmam ve bunun yerine başka bir ders almam tavsiye edildi. Bu nedenle, bazı kontroller yapmak ve türe bağlı olarak farklı eylemler yapmak yerine, sınıfın kendisini nasıl işleyeceğini bilmesini sağlayın ...

örneğin Obj, ISpecialType veya IType olabilir;

her ikisinin de tanımlı bir DoStuff () yöntemi vardır. IType için yalnızca geri dönebilir veya özel şeyler yapabilir, oysa ISpecialType başka şeyler yapabilir.

Bu daha sonra herhangi bir atama işlemini tamamen kaldırır, kodu daha temiz ve bakımı kolaylaştırır ve sınıf kendi görevlerini nasıl yapacağını bilir.


Evet, eğer tip testleri doğru ise tek yapacağım, üzerinde belirli bir arayüz metodu çağırmak olduğu için, bu arayüz metodunu temel sınıfa taşıyabilir ve varsayılan olarak hiçbir şey yapmamasını sağlayabilirim. Bu, türü test etmek için sanal bir işlev oluşturmaktan daha zarif olabilir.
JubJub

Abatishchev'in yorumlarının ardından Binary Worrier'a benzer bir test yaptım ve 10.000.000 itterasyon üzerinde yalnızca 60ms'lik bir fark buldum.
Ian

1
Vay canına, yardımın için teşekkürler. Sınıf yapısını yeniden düzenlemek için uygun görünmediği sürece, şimdilik tür kontrol operatörlerini kullanmaya devam edeceğimi düşünüyorum. Gereksiz olarak yayın yapmak istemediğim için Andrew'un önerdiği gibi 'as' operatörünü kullanacağım.
JubJub

15

İki tür karşılaştırması olasılığı üzerine bir performans karşılaştırması yaptım

  1. myobject.GetType () == typeof (Sınıfım)
  2. myobject MyClass

Sonuç: "is" kullanımı yaklaşık 10 kat daha hızlıdır !!!

Çıktı:

Tür Karşılaştırma Süresi: 00: 00: 00.456

Is Karşılaştırma Süresi: 00: 00: 00.042

Kodum:

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

13

Andrew Hare'in iskontrol gerçekleştirdiğinizde ve ardından cast geçerliyken performans kaybıyla ilgili olarak belirttiği nokta , ancak C # 7.0'da daha sonra ek atmayı önlemek için cadı kalıbı eşleşmesini kontrol edebiliriz:

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

Daha fazla, birden çok tür arasında kontrol etmeniz gerekirse, C # 7.0 kalıp eşleştirme yapıları artık switchtürler üzerinde yapmanıza olanak tanır :

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

Buradaki belgelerde C # 'da kalıp eşleştirmesi hakkında daha fazla bilgi edinebilirsiniz .


1
Elbette geçerli bir çözüm, ancak bu C # kalıp eşleştirme özelliği, bunun gibi "özellik-kıskançlık" kodunu teşvik ettiğinde beni üzüyor. Elbette, yalnızca türetilen nesnelerin kendi alanlarını nasıl hesaplayacaklarını "bildikleri" ve sonra sadece değeri döndürdükleri mantığın kapsüllenmesi için çabalamalıyız?
Dib

2
SO, bir çerçevenin, platformun vb. Daha yeni sürümleri için geçerli olan yanıtlar için filtre düğmelerine (soruda) ihtiyaç duyar. Bu yanıt, C # 7 için doğru olanın temelini oluşturur.
Nick Westgate,

2
@Dib OOP idealleri, kontrol etmediğiniz türler / sınıflar / arabirimlerle çalışırken pencereden atılır. Bu yaklaşım aynı zamanda, tamamen farklı türlerdeki birçok değerden birini döndürebilen bir işlevin sonucunu işlerken de yararlıdır (çünkü C # henüz birleşim türlerini desteklemiyor - gibi kitaplıkları kullanabilirsiniz, OneOf<T...>ancak bunların büyük eksiklikleri vardır) .
Dai

5

Herhangi birinin merak etmesi durumunda, i5-4200U CPU'lu bir dizüstü bilgisayarda komut dosyası çalışma zamanı sürümü .NET4.6 (Experimantal) ile Unity Engine 2017.1'de testler yaptım. Sonuçlar:

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

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


Makale bağlantısı kesildi.
James Wilkins

@ James bağlantısı yeniden canlandı.
Gru

İyi şeyler - ama size olumsuz oy vermedim (aslında yine de olumlu oy verdim); Merak ediyorsan diye. :)
James Wilkins

-3

Her zaman böyle kontrol etmekten kaçınmam ve onun yerine başka bir dersim olması tavsiye edildi. Bu nedenle, bazı kontroller yapmak ve türe bağlı olarak farklı eylemler yapmak yerine, sınıfın kendisini nasıl işleyeceğini bilmesini sağlayın ...

örneğin Obj, ISpecialType veya IType olabilir;

her ikisinin de tanımlı bir DoStuff () yöntemi vardır. IType için yalnızca geri dönebilir veya özel şeyler yapabilir, oysa ISpecialType başka şeyler yapabilir.

Bu daha sonra herhangi bir atama işlemini tamamen kaldırır, kodu daha temiz ve bakımı kolaylaştırır ve sınıf kendi görevlerini nasıl yapacağını bilir.


1
Bu soruya cevap vermiyor. Her neyse, sınıflar bağlam eksikliği nedeniyle kendilerini nasıl işleyeceklerini her zaman bilemeyebilirler. Bazı yöntem / işlev hataları işlemek için yeterli içeriğe sahip olana kadar istisnaların çağrı zincirinde yukarı çıkmasına izin verdiğimizde, istisna işlemeye benzer mantığı uygularız.
Vakhtang
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.