Aracılığıyla paylaş


C# ve .NET içinde devralma

Bu öğreticide C# dilinde devralma işlemleri tanıtılmıştır. Devralma, belirli işlevler (veri ve davranış) sağlayan bir temel sınıf tanımlamanızı ve bu işlevselliği devralan veya geçersiz kılan türetilmiş sınıfları tanımlamanızı sağlayan nesne odaklı programlama dillerinin bir özelliğidir.

Önkoşullar

  • Windows için Visual Studio'yu öneririz. Visual Studio indirmeleri sayfasından ücretsiz bir sürüm indirebilirsiniz. Visual Studio ,NET SDK'sını içerir.
  • Visual Studio Code düzenleyicisini C# DevKit ile de kullanabilirsiniz. En son .NET SDK'sını ayrıca yüklemeniz gerekir.
  • Farklı bir düzenleyici tercih ediyorsanız en son .NET SDK'sını yüklemeniz gerekir.

Örnekleri çalıştırma

Bu öğreticideki örnekleri oluşturmak ve çalıştırmak için komut satırından dotnet yardımcı programını kullanırsınız. Her örnek için şu adımları izleyin:

  1. Örneği depolamak için bir dizin oluşturun.

  2. Yeni bir .NET Core projesi oluşturmak için komut istemine dotnet yeni konsol komutunu girin.

  3. Örnekteki kodu kopyalayıp kod düzenleyicinize yapıştırın.

  4. Projenin bağımlılıklarını yüklemek veya geri yüklemek için komut satırından dotnet restore komutunu girin.

    , , dotnet publishve dotnet packgibi dotnet testdotnet rundotnet builddotnet newgeri yükleme gerektiren tüm komutlar tarafından örtük olarak çalıştırıldığından, komutunu çalıştırmanız dotnet restore gerekmez. Örtük geri yüklemeyi devre dışı bırakmak için seçeneğini kullanın --no-restore .

    Komutudotnet restore, Azure DevOps Services'teki sürekli tümleştirme derlemeleri veya geri yüklemenin ne zaman gerçekleştiğini açıkça denetlemesi gereken derleme sistemleri gibi açıkça geri yüklemenin anlamlı olduğu bazı senaryolarda hala yararlıdır.

    NuGet akışlarını yönetme hakkında bilgi için belgelere dotnet restore bakın.

  5. Örneği derlemek ve yürütmek için dotnet run komutunu girin.

Arka plan: Devralma nedir?

Devralma , nesne odaklı programlamanın temel özniteliklerinden biridir. Bir üst sınıfın davranışını yeniden kullanan (devralan), genişleten veya değiştiren bir alt sınıf tanımlamanızı sağlar. Üyeleri devralınan sınıfa temel sınıf adı verilir. Temel sınıfın üyelerini devralan sınıf, türetilmiş sınıf olarak adlandırılır.

C# ve .NET yalnızca tek devralmayı destekler. Yani, bir sınıf yalnızca tek bir sınıftan devralabilir. Ancak, devralma geçişlidir ve bir tür kümesi için devralma hiyerarşisi tanımlamanızı sağlar. Başka bir deyişle, türü D , türünden Cdevralan Bve temel sınıf türünden devralan türünden Adevralabilir. Devralma geçişli olduğundan, türü A üyeleri yazabilirsiniz D.

Temel sınıfın tüm üyeleri türetilmiş sınıflar tarafından devralınır. Aşağıdaki üyeler devralınmıyor:

Temel sınıfın diğer tüm üyeleri türetilmiş sınıflar tarafından devralınmış olsa da, görünür olup olmadıkları erişilebilirliklerine bağlıdır. Bir üyenin erişilebilirliği, türetilmiş sınıflar için görünürlüğünü aşağıdaki gibi etkiler:

  • Özel üyeler yalnızca temel sınıflarında iç içe geçmiş türetilmiş sınıflarda görünür. Aksi takdirde, türetilmiş sınıflarda görünmezler. Aşağıdaki örnekte, A.B öğesinden ve C öğesinden Atüretilen iç içe geçmiş bir sınıftırA. Özel A._value alan A.B.'de görünür. Ancak, yönteminden C.GetValue açıklamaları kaldırır ve örneği derlemeye çalışırsanız, derleyici hatası CS0122 oluşturur: "'A._value' koruma düzeyinden dolayı erişilemez."

    public class A
    {
        private int _value = 10;
    
        public class B : A
        {
            public int GetValue()
            {
                return _value;
            }
        }
    }
    
    public class C : A
    {
        //    public int GetValue()
        //    {
        //        return _value;
        //    }
    }
    
    public class AccessExample
    {
        public static void Main(string[] args)
        {
            var b = new A.B();
            Console.WriteLine(b.GetValue());
        }
    }
    // The example displays the following output:
    //       10
    
  • Korumalı üyeler yalnızca türetilmiş sınıflarda görünür.

  • İç üyeler yalnızca temel sınıfla aynı derlemede bulunan türetilmiş sınıflarda görünür. Bunlar, temel sınıftan farklı bir derlemede bulunan türetilmiş sınıflarda görünmez.

  • Ortak üyeler türetilmiş sınıflarda görünür ve türetilmiş sınıfın ortak arabiriminin bir parçasıdır. Genel devralınan üyeler, türetilmiş sınıfta tanımlanmış gibi çağrılabilir. Aşağıdaki örnekte, sınıfı A adlı Method1bir yöntem tanımlar ve sınıfı B sınıfından Adevralır. Örnek daha sonra üzerinde Bbir örnek yöntemiymiş gibi çağırırMethod1.

    public class A
    {
        public void Method1()
        {
            // Method implementation.
        }
    }
    
    public class B : A
    { }
    
    public class Example
    {
        public static void Main()
        {
            B b = new ();
            b.Method1();
        }
    }
    

Türetilmiş sınıflar, alternatif bir uygulama sağlayarak devralınan üyeleri de geçersiz kılabilir . Bir üyeyi geçersiz kılabilmek için, temel sınıftaki üye sanal anahtar sözcükle işaretlenmelidir. Varsayılan olarak, temel sınıf üyeleri olarak virtual işaretlenmez ve geçersiz kılınamaz. Aşağıdaki örnekte olduğu gibi sanal olmayan bir üyeyi geçersiz kılmaya çalışmak, derleyici hatası CS0506 oluşturur: "<üye>, sanal, soyut veya geçersiz kılma olarak işaretlenmediğinden devralınan üyeyi <> geçersiz kılamaz."

public class A
{
    public void Method1()
    {
        // Do something.
    }
}

public class B : A
{
    public override void Method1() // Generates CS0506.
    {
        // Do something else.
    }
}

Bazı durumlarda, türetilmiş bir sınıf temel sınıf uygulamasını geçersiz kılmalıdır . Soyut anahtar sözcüğüyle işaretlenmiş temel sınıf üyeleri, türetilmiş sınıfların bunları geçersiz kılmasını gerektirir. Aşağıdaki örneği derlemeye çalışmak, "<sınıf> devralınan soyut üye <üyesini> uygulamaz" derleyici hatası CS0534 oluşturur, çünkü sınıfı B için A.Method1hiçbir uygulama sağlamaz.

public abstract class A
{
    public abstract void Method1();
}

public class B : A // Generates CS0534.
{
    public void Method3()
    {
        // Do something.
    }
}

Devralma yalnızca sınıflar ve arabirimler için geçerlidir. Diğer tür kategorileri (yapılar, temsilciler ve sabit listeleri) devralmayı desteklemez. Bu kurallar nedeniyle, aşağıdaki örnekte olduğu gibi kod derlemeye çalışmak derleyici hatası CS0527 oluşturur: "Arabirim listesindeki 'ValueType' türü bir arabirim değil." Hata iletisi, bir yapının uyguladığı arabirimleri tanımlayabilmenize rağmen devralma işleminin desteklenmediğini gösterir.

public struct ValueStructure : ValueType // Generates CS0527.
{
}

Örtük devralma

Tek devralma yoluyla devralabilecekleri türlerin yanı sıra, .NET tür sistemindeki tüm türler örtük olarak veya Object ondan türetilmiş bir türü devralır. ortak işlevselliği Object her tür için kullanılabilir.

Örtük devralmanın ne anlama geldiğini görmek için, yalnızca boş bir sınıf SimpleClasstanımı olan yeni bir sınıf tanımlayalım:

public class SimpleClass
{ }

Daha sonra türe ait SimpleClass üyelerin listesini almak için yansımayı (bu tür hakkında bilgi almak için bir türün meta verilerini incelemenize olanak sağlayan) kullanabilirsiniz. Sınıfınızda SimpleClass herhangi bir üye tanımlamamış olmanıza rağmen, örnekten elde ettiğiniz çıkış aslında dokuz üyesi olduğunu gösterir. Bu üyelerden biri, C# derleyicisi tarafından tür için SimpleClass otomatik olarak sağlanan parametresiz (veya varsayılan) bir oluşturucudur. Kalan sekiz, .NET tür sistemindeki tüm sınıfların ve arabirimlerin örtük olarak devraldığı türün üyeleridir Object.

using System.Reflection;

public class SimpleClassExample
{
    public static void Main()
    {
        Type t = typeof(SimpleClass);
        BindingFlags flags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public |
                             BindingFlags.NonPublic | BindingFlags.FlattenHierarchy;
        MemberInfo[] members = t.GetMembers(flags);
        Console.WriteLine($"Type {t.Name} has {members.Length} members: ");
        foreach (MemberInfo member in members)
        {
            string access = "";
            string stat = "";
            var method = member as MethodBase;
            if (method != null)
            {
                if (method.IsPublic)
                    access = " Public";
                else if (method.IsPrivate)
                    access = " Private";
                else if (method.IsFamily)
                    access = " Protected";
                else if (method.IsAssembly)
                    access = " Internal";
                else if (method.IsFamilyOrAssembly)
                    access = " Protected Internal ";
                if (method.IsStatic)
                    stat = " Static";
            }
            string output = $"{member.Name} ({member.MemberType}): {access}{stat}, Declared by {member.DeclaringType}";
            Console.WriteLine(output);
        }
    }
}
// The example displays the following output:
//	Type SimpleClass has 9 members:
//	ToString (Method):  Public, Declared by System.Object
//	Equals (Method):  Public, Declared by System.Object
//	Equals (Method):  Public Static, Declared by System.Object
//	ReferenceEquals (Method):  Public Static, Declared by System.Object
//	GetHashCode (Method):  Public, Declared by System.Object
//	GetType (Method):  Public, Declared by System.Object
//	Finalize (Method):  Internal, Declared by System.Object
//	MemberwiseClone (Method):  Internal, Declared by System.Object
//	.ctor (Constructor):  Public, Declared by SimpleClass

sınıfından Object örtük devralma, bu yöntemleri sınıfı için SimpleClass kullanılabilir hale getirir:

  • Bir nesneyi dize gösterimine dönüştüren SimpleClass public ToString yöntemi, tam tür adını döndürür. Bu durumda, ToString yöntemi "SimpleClass" dizesini döndürür.

  • İki nesnenin eşitliğini test eden üç yöntem: ortak örnek Equals(Object) yöntemi, genel statik Equals(Object, Object) yöntem ve genel statik ReferenceEquals(Object, Object) yöntem. Varsayılan olarak, bu yöntemler başvuru eşitliğini test eder; yani eşit olmak için iki nesne değişkeninin aynı nesneye başvurması gerekir.

  • Türün bir örneğinin karma koleksiyonlarda kullanılmasına izin veren bir değeri hesaplayan public GetHashCode yöntemi.

  • Türünü temsil SimpleClass eden bir Type nesne döndüren public GetType yöntemi.

  • Bir nesnenin belleği çöp toplayıcı tarafından geri kazanılmadan önce yönetilmeyen kaynakları serbest bırakmak için tasarlanmış korumalı Finalize yöntem.

  • Geçerli nesnenin sığ bir kopyasını oluşturan korumalı MemberwiseClone yöntem.

Örtük devralma nedeniyle, bir nesneden devralınan herhangi bir SimpleClass üyeyi sınıfta tanımlanmış SimpleClass bir üye gibi çağırabilirsiniz. Örneğin, aşağıdaki örnekte öğesinden Objectdevralınan SimpleClass.ToStringSimpleClass yöntemi çağrılır.

public class EmptyClass
{ }

public class ClassNameExample
{
    public static void Main()
    {
        EmptyClass sc = new();
        Console.WriteLine(sc.ToString());
    }
}
// The example displays the following output:
//        EmptyClass

Aşağıdaki tabloda, C# dilinde oluşturabileceğiniz türlerin kategorileri ve örtük olarak devraldıkları türler listelenmiştir. Her temel tür, devralma aracılığıyla örtük olarak türetilmiş türler için farklı bir üye kümesi sağlar.

Tür kategorisi Örtük olarak devralır:
class Object
struct ValueType, Object
enum Enum, ValueType, Object
temsilci MulticastDelegate, Delegate, Object

Devralma ve "bir" ilişkisi

Normalde devralma, temel sınıf ile türetilmiş sınıfların temel sınıfın özel sürümleri olduğu bir veya daha fazla türetilmiş sınıf arasındaki "is a" ilişkisini ifade etmek için kullanılır; türetilmiş sınıf, temel sınıfın bir türüdür. Örneğin, Publication sınıfı herhangi bir türde yayını temsil eder ve BookMagazine sınıfları belirli yayın türlerini temsil eder.

Not

Bir sınıf veya yapı bir veya daha fazla arabirim uygulayabilir. Arabirim uygulaması genellikle tek devralma için geçici bir çözüm olarak veya yapılarla devralmayı kullanmanın bir yolu olarak sunulsa da, arabirim ile uygulama türü arasında devralma yerine farklı bir ilişki (bir "yapabilir" ilişkisi) ifade etmek amaçlanmıştır. Arabirim, işlevselliğin bir alt kümesini tanımlar (eşitliği test etme, nesneleri karşılaştırma veya sıralama ya da kültüre duyarlı ayrıştırma ve biçimlendirmeyi destekleme gibi) arabirimin uygulama türleri için kullanılabilir hale getirdiği.

"is a" ifadesinin bir tür ile bu türün belirli bir örneğini oluşturma arasındaki ilişkiyi de ifade ettiğini unutmayın. Aşağıdaki örnekte, Automobile üç benzersiz salt okunur özelliği olan bir sınıftır: Make, otomobil üreticisi; Model, otomobil türü; ve Year, üretim yılı. Sınıfınızda Automobile ayrıca bağımsız değişkenleri özellik değerlerine atanmış bir oluşturucu vardır ve sınıfı yerine Automobile örneği benzersiz olarak tanımlayan Automobile bir dize oluşturmak için yöntemini geçersiz kılarObject.ToString.

public class Automobile
{
    public Automobile(string make, string model, int year)
    {
        if (make == null)
            throw new ArgumentNullException(nameof(make), "The make cannot be null.");
        else if (string.IsNullOrWhiteSpace(make))
            throw new ArgumentException("make cannot be an empty string or have space characters only.");
        Make = make;

        if (model == null)
            throw new ArgumentNullException(nameof(model), "The model cannot be null.");
        else if (string.IsNullOrWhiteSpace(model))
            throw new ArgumentException("model cannot be an empty string or have space characters only.");
        Model = model;

        if (year < 1857 || year > DateTime.Now.Year + 2)
            throw new ArgumentException("The year is out of range.");
        Year = year;
    }

    public string Make { get; }

    public string Model { get; }

    public int Year { get; }

    public override string ToString() => $"{Year} {Make} {Model}";
}

Bu durumda, belirli araba modellerini ve modellerini temsil etmek için devralmaya güvenmemelisiniz. Örneğin, Packard Motorlu Araba Şirketi tarafından üretilen otomobilleri temsil eden bir Packard tür tanımlamanız gerekmez. Bunun yerine, aşağıdaki örnekte olduğu gibi sınıf oluşturucusunun geçirdiği uygun değerlere sahip bir Automobile nesne oluşturarak bunları temsil edebilirsiniz.

using System;

public class Example
{
    public static void Main()
    {
        var packard = new Automobile("Packard", "Custom Eight", 1948);
        Console.WriteLine(packard);
    }
}
// The example displays the following output:
//        1948 Packard Custom Eight

Devralmayı temel alan bir ilişki en iyi temel sınıfa ve temel sınıfa ek üyeler ekleyen veya temel sınıfta mevcut olmayan ek işlevler gerektiren türetilmiş sınıflara uygulanır.

Temel sınıfı ve türetilmiş sınıfları tasarlama

Şimdi temel sınıfı ve türetilmiş sınıflarını tasarlama işlemine göz atalım. Bu bölümde, kitap, dergi, gazete, Publicationgünlük, makale vb. her türlü yayını temsil eden bir temel sınıf tanımlayacaksınız. Ayrıca öğesinden Publicationtüretilen bir Book sınıf da tanımlayacaksınız. Örneği, , Journal, Newspaperve Articlegibi Magazinediğer türetilmiş sınıfları tanımlamak için kolayca genişletebilirsiniz.

Temel Yayın sınıfı

Sınıfınızı Publication tasarlarken birkaç tasarım kararı almanız gerekir:

  • Temel Publication sınıfınıza eklenecek üyeler ve üyelerin Publication yöntem uygulamaları sağlayıp sağlamadığı veya türetilmiş sınıfları için şablon olarak hizmet veren soyut bir temel sınıf olup olmadığı Publication .

    Bu durumda, Publication sınıfı yöntem uygulamaları sağlar. Soyut temel sınıflar ve bunların türetilmiş sınıfları tasarlama bölümü, türetilmiş sınıfların geçersiz kılması gereken yöntemleri tanımlamak için soyut temel sınıf kullanan bir örnek içerir. Türetilmiş sınıflar türetilen türe uygun herhangi bir uygulama sağlamak için ücretsizdir.

    Kodu yeniden kullanabilme (yani, birden çok türetilmiş sınıf, temel sınıf yöntemlerinin bildirimini ve uygulamasını paylaşır ve bunları geçersiz kılmaya gerek yoktur) soyut olmayan temel sınıfların bir avantajıdır. Bu nedenle, kodlarının bazı veya en özel Publication türler tarafından paylaşılma olasılığı varsa üyeleri eklemeniz Publication gerekir. Temel sınıf uygulamalarını verimli bir şekilde sağlamazsanız, temel sınıfta tek bir uygulama yerine türetilmiş sınıflarda büyük ölçüde özdeş üye uygulamaları sağlamanız gerekir. Yinelenen kodu birden çok konumda tutma gereksinimi olası bir hata kaynağıdır.

    Hem kodun yeniden kullanılmasını en üst düzeye çıkarmak hem de mantıksal ve sezgisel bir devralma hiyerarşisi oluşturmak için sınıfına Publication yalnızca tüm yayınlarda veya yayınlarda ortak olan verileri ve işlevleri eklediğinizden emin olmak istersiniz. Türetilmiş sınıflar daha sonra temsil ettikleri belirli yayın türlerine özgü üyeler uygular.

  • Sınıf hiyerarşinizi ne kadar genişletirsiniz? Yalnızca bir temel sınıf ve bir veya daha fazla türetilmiş sınıf yerine üç veya daha fazla sınıf hiyerarşisi geliştirmek istiyor musunuz? Örneğin, Publication bir temel sınıfı Periodicalolabilir. Bu da , ve Newspapertemel sınıfıdırMagazineJournal.

    Örneğin, küçük bir Publication sınıfın hiyerarşisini ve türetilmiş tek bir sınıfını Bookkullanacaksınız. örneğini kolayca genişleterek ve Articlegibi Magazine 'den Publicationtüretilen bir dizi ek sınıf oluşturabilirsiniz.

  • Temel sınıfın örneğini oluşturmanın mantıklı olup olmadığı. Aksi takdirde, soyut anahtar sözcüğünü sınıfına uygulamanız gerekir. Aksi takdirde, sınıfınız Publication sınıf oluşturucu çağrılarak örneği oluşturulabilir. Sınıf oluşturucusunun doğrudan çağrısıyla anahtar sözcüğüyle abstract işaretlenmiş bir sınıfın örneğini oluşturmaya çalışılırsa, C# derleyicisi CS0144 "Soyut sınıfın veya arabirimin örneği oluşturulamıyor" hatasını oluşturur. Yansıma kullanılarak sınıfın örneğini oluşturma girişiminde bulunulsa, yansıma yöntemi bir MemberAccessExceptionoluşturur.

    Varsayılan olarak, bir temel sınıf sınıf oluşturucu çağrılarak örneklenebilir. Açıkça bir sınıf oluşturucu tanımlamanız gerekmez. Temel sınıfın kaynak kodunda yoksa, C# derleyicisi otomatik olarak bir varsayılan (parametresiz) oluşturucu sağlar.

    Örneğiniz için örneği oluşturulamaması için sınıfı soyut olarak işaretleyeceksinizPublication. abstract Herhangi bir abstract yöntemi olmayan bir sınıf, bu sınıfın çeşitli somut sınıflar arasında paylaşılan soyut bir kavramı temsil ettiğini gösterir (örneğin Book, Journal).

  • Türetilmiş sınıfların belirli üyelerin temel sınıf uygulamasını devralması gerekip gerekmediği, temel sınıf uygulamasını geçersiz kılma seçeneğine sahip olup olmadıkları veya bir uygulama sağlamaları gerekip gerekmediği. Soyut anahtar sözcüğünü kullanarak türetilmiş sınıfları bir uygulama sağlamaya zorlarsınız. Türetilmiş sınıfların temel sınıf yöntemini geçersiz kılmasına izin vermek için sanal anahtar sözcüğünü kullanırsınız. Varsayılan olarak, temel sınıfta tanımlanan yöntemler geçersiz kılınamaz.

    Sınıfın Publication herhangi bir abstract yöntemi yoktur, ancak sınıfın kendisidir abstract.

  • Türetilmiş bir sınıfın devralma hiyerarşisindeki son sınıfı temsil edip etmediği ve ek türetilmiş sınıflar için temel sınıf olarak kullanılıp kullanılamayacağı. Varsayılan olarak, herhangi bir sınıf temel sınıf olarak hizmet verebilir. Bir sınıfın herhangi bir ek sınıf için temel sınıf olarak hizmet veremeyeceğini belirtmek için sealed anahtar sözcüğünü uygulayabilirsiniz. Korumalı sınıf tarafından oluşturulan bir derleyici hatası CS0509'dan türetmeye çalışılırken, "sealed typeName> türünden <türetilemez."

    Örneğiniz için türetilmiş sınıfınızı olarak sealedişaretleyeceksiniz.

Aşağıdaki örnek, sınıfın Publication kaynak kodunun yanı sıra özelliği tarafından döndürülen bir PublicationType numaralandırmayı Publication.PublicationType gösterir. sınıfından devraldığı ObjectPublication üyelere ek olarak, sınıfı aşağıdaki benzersiz üyeleri ve üye geçersiz kılmalarını tanımlar:


public enum PublicationType { Misc, Book, Magazine, Article };

public abstract class Publication
{
    private bool _published = false;
    private DateTime _datePublished;
    private int _totalPages;

    public Publication(string title, string publisher, PublicationType type)
    {
        if (string.IsNullOrWhiteSpace(publisher))
            throw new ArgumentException("The publisher is required.");
        Publisher = publisher;

        if (string.IsNullOrWhiteSpace(title))
            throw new ArgumentException("The title is required.");
        Title = title;

        Type = type;
    }

    public string Publisher { get; }

    public string Title { get; }

    public PublicationType Type { get; }

    public string? CopyrightName { get; private set; }

    public int CopyrightDate { get; private set; }

    public int Pages
    {
        get { return _totalPages; }
        set
        {
            if (value <= 0)
                throw new ArgumentOutOfRangeException(nameof(value), "The number of pages cannot be zero or negative.");
            _totalPages = value;
        }
    }

    public string GetPublicationDate()
    {
        if (!_published)
            return "NYP";
        else
            return _datePublished.ToString("d");
    }

    public void Publish(DateTime datePublished)
    {
        _published = true;
        _datePublished = datePublished;
    }

    public void Copyright(string copyrightName, int copyrightDate)
    {
        if (string.IsNullOrWhiteSpace(copyrightName))
            throw new ArgumentException("The name of the copyright holder is required.");
        CopyrightName = copyrightName;

        int currentYear = DateTime.Now.Year;
        if (copyrightDate < currentYear - 10 || copyrightDate > currentYear + 2)
            throw new ArgumentOutOfRangeException($"The copyright year must be between {currentYear - 10} and {currentYear + 1}");
        CopyrightDate = copyrightDate;
    }

    public override string ToString() => Title;
}
  • Oluşturucu

    Publication sınıfı olduğundanabstract, aşağıdaki örnekte olduğu gibi doğrudan koddan örneği oluşturulamaz:

    var publication = new Publication("Tiddlywinks for Experts", "Fun and Games",
                                      PublicationType.Book);
    

    Ancak, örnek oluşturucu doğrudan türetilmiş sınıf oluşturucularından çağrılabilir, sınıfın Book kaynak kodunda gösterildiği gibi.

  • Yayınla ilgili iki özellik

    Title, oluşturucu çağrılarak Publication değeri sağlanan salt okunur String bir özelliktir.

    Pages , yayının toplam sayfa sayısını gösteren bir okuma-yazma Int32 özelliğidir. Değer adlı totalPagesözel bir alanda depolanır. Pozitif bir sayı olmalıdır veya bir ArgumentOutOfRangeException atılır.

  • Yayımcıyla ilgili üyeler

    İki salt okunur özellik Publisher ve Type. Değerler başlangıçta sınıf oluşturucusunun Publication çağrısı tarafından sağlanır.

  • Yayımlamayla ilgili üyeler

    İki yöntem ve PublishGetPublicationDate, yayın tarihini ayarlayıp döndürür. Publish yöntemi çağrıldığında özel published bir bayrak true ayarlar ve özel alana bağımsız değişken datePublished olarak geçirilen tarihi atar. yöntemi, GetPublicationDate bayrağı falseise published "NYP" dizesini ve ise truealanın değerini datePublished döndürür.

  • Telif hakkıyla ilgili üyeler

    yöntemi, Copyright telif hakkı sahibinin adını ve telif hakkı yılını bağımsız değişken olarak alır ve bunları ve CopyrightDate özelliklerine CopyrightName atar.

  • Yöntemi geçersiz ToString kılma

    Bir tür yöntemini geçersiz kılmazsa Object.ToString , türün tam adını döndürür; bu, bir örneği diğerinden ayırt etmek için çok az kullanılır. Publication sınıfı, özelliğinin değerini döndürmek Title için geçersiz kılarObject.ToString.

Aşağıdaki şekilde, temel Publication sınıfınızla örtük olarak devralınan Object sınıfı arasındaki ilişki gösterilmektedir.

Nesne ve Yayın sınıfları

Sınıfı Book

sınıfı, Book bir kitabı özel bir yayın türü olarak temsil eder. Aşağıdaki örnekte sınıfın kaynak kodu gösterilmektedir Book .

using System;

public sealed class Book : Publication
{
    public Book(string title, string author, string publisher) :
           this(title, string.Empty, author, publisher)
    { }

    public Book(string title, string isbn, string author, string publisher) : base(title, publisher, PublicationType.Book)
    {
        // isbn argument must be a 10- or 13-character numeric string without "-" characters.
        // We could also determine whether the ISBN is valid by comparing its checksum digit
        // with a computed checksum.
        //
        if (!string.IsNullOrEmpty(isbn))
        {
            // Determine if ISBN length is correct.
            if (!(isbn.Length == 10 | isbn.Length == 13))
                throw new ArgumentException("The ISBN must be a 10- or 13-character numeric string.");
            if (!ulong.TryParse(isbn, out _))
                throw new ArgumentException("The ISBN can consist of numeric characters only.");
        }
        ISBN = isbn;

        Author = author;
    }

    public string ISBN { get; }

    public string Author { get; }

    public decimal Price { get; private set; }

    // A three-digit ISO currency symbol.
    public string? Currency { get; private set; }

    // Returns the old price, and sets a new price.
    public decimal SetPrice(decimal price, string currency)
    {
        if (price < 0)
            throw new ArgumentOutOfRangeException(nameof(price), "The price cannot be negative.");
        decimal oldValue = Price;
        Price = price;

        if (currency.Length != 3)
            throw new ArgumentException("The ISO currency symbol is a 3-character string.");
        Currency = currency;

        return oldValue;
    }

    public override bool Equals(object? obj)
    {
        if (obj is not Book book)
            return false;
        else
            return ISBN == book.ISBN;
    }

    public override int GetHashCode() => ISBN.GetHashCode();

    public override string ToString() => $"{(string.IsNullOrEmpty(Author) ? "" : Author + ", ")}{Title}";
}

sınıfından devraldığı PublicationBook üyelere ek olarak, sınıfı aşağıdaki benzersiz üyeleri ve üye geçersiz kılmalarını tanımlar:

  • İki oluşturucu

    İki Book oluşturucu üç ortak parametreyi paylaşır. başlık ve yayımcı olmak üzere iki, oluşturucunun parametrelerine Publication karşılık gelir. Üçüncüsü, ortak Author sabit bir özelliğe depolanan yazardır. Bir oluşturucu, otomatik özelliğinde ISBN depolanan bir isbn parametresi içerir.

    İlk oluşturucu, diğer oluşturucuyu çağırmak için bu anahtar sözcüğü kullanır. Oluşturucu zincirleme, oluşturucuları tanımlamada yaygın bir desendir. Daha az parametreye sahip oluşturucular, oluşturucuyu en fazla sayıda parametreyle çağırırken varsayılan değerler sağlar.

    İkinci oluşturucu, başlık ve yayımcı adını temel sınıf oluşturucusna geçirmek için temel anahtar sözcüğünü kullanır. Kaynak kodunuzda bir temel sınıf oluşturucusunda açık bir çağrı yapmazsanız, C# derleyicisi otomatik olarak temel sınıfın varsayılan veya parametresiz oluşturucusunun çağrısını sağlar.

  • Nesnenin Uluslararası Standart Kitap Numarası'nı Book (benzersiz bir 10 veya 13 basamaklı sayı) döndüren salt ISBN okunur bir özellik. ISBN, oluşturuculardan Book birine bağımsız değişken olarak sağlanır. ISBN, derleyici tarafından otomatik olarak oluşturulan özel bir yedekleme alanında depolanır.

  • Salt Author okunur bir özellik. Yazar adı, her iki Book oluşturucu için de bağımsız değişken olarak sağlanır ve özelliğinde depolanır.

  • Salt okunur fiyatla ilgili iki özellik Price ve Currency. Değerleri bir SetPrice yöntem çağrısında bağımsız değişken olarak sağlanır. Currency Özelliği, üç basamaklı ISO para birimi simgesidir (örneğin, ABD doları için USD). ISO para birimi simgeleri özelliğinden ISOCurrencySymbol alınabilir. Bu özelliklerin her ikisi de dışarıdan salt okunur olsa da, her ikisi de sınıfındaki Book kod tarafından ayarlanabilir.

  • SetPrice ve Currency özelliklerinin değerlerini Price ayarlayan bir yöntem. Bu değerler aynı özellikler tarafından döndürülür.

  • yöntemine ToString (öğesinden devralınanPublication) ve ve GetHashCode yöntemlerine Object.Equals(Object) (öğesinden devralınanObject) geçersiz kılar.

    Geçersiz kılınmadığı sürece, Object.Equals(Object) yöntem başvuru eşitliğini sınar. Diğer bir ifadeyle, aynı nesneye başvuruda bulunan iki nesne değişkeninin eşit olduğu kabul edilir. Book Sınıfında ise aynı ISBN'ye sahip olan iki Book nesne eşit olmalıdır.

    yöntemini geçersiz kıldığınızda, çalışma zamanının Object.Equals(Object)GetHashCode öğeleri verimli bir şekilde almak için karma koleksiyonlarda depolamak için kullandığı bir değeri döndüren yöntemini de geçersiz kılmanız gerekir. Karma kod, eşitlik testiyle tutarlı bir değer döndürmelidir. İki Book nesnenin ISBN özellikleri eşitse döndürmeyi true geçersiz kıldığınızdanObject.Equals(Object), özelliği tarafından ISBN döndürülen dizenin GetHashCode yöntemini çağırarak hesaplanan karma kodu döndürürsiniz.

Aşağıdaki şekilde, sınıfı ile Publicationtemel sınıfı arasındaki Book ilişki gösterilmektedir.

Yayın ve Kitap sınıfları

Artık bir Book nesnenin örneğini oluşturabilir, hem benzersiz hem de devralınan üyeleri çağırabilir ve aşağıdaki örnekte gösterildiği gibi türünde veya türünde PublicationBookbir parametre bekleyen bir yönteme bağımsız değişken olarak geçirebilirsiniz.

public class ClassExample
{
    public static void Main()
    {
        var book = new Book("The Tempest", "0971655819", "Shakespeare, William",
                            "Public Domain Press");
        ShowPublicationInfo(book);
        book.Publish(new DateTime(2016, 8, 18));
        ShowPublicationInfo(book);

        var book2 = new Book("The Tempest", "Classic Works Press", "Shakespeare, William");
        Console.Write($"{book.Title} and {book2.Title} are the same publication: " +
              $"{((Publication)book).Equals(book2)}");
    }

    public static void ShowPublicationInfo(Publication pub)
    {
        string pubDate = pub.GetPublicationDate();
        Console.WriteLine($"{pub.Title}, " +
                  $"{(pubDate == "NYP" ? "Not Yet Published" : "published on " + pubDate):d} by {pub.Publisher}");
    }
}
// The example displays the following output:
//        The Tempest, Not Yet Published by Public Domain Press
//        The Tempest, published on 8/18/2016 by Public Domain Press
//        The Tempest and The Tempest are the same publication: False

Soyut temel sınıflar ve türetilmiş sınıfları tasarlama

Önceki örnekte, türetilmiş sınıfların kodu paylaşmasına izin vermek için bir dizi yöntem için bir uygulama sağlayan bir temel sınıf tanımlamıştınız. Ancak çoğu durumda temel sınıfın bir uygulama sağlaması beklenmemektedir. Bunun yerine, temel sınıf soyut yöntemleri bildiren bir soyut sınıftır; türetilmiş her sınıfın uygulaması gereken üyeleri tanımlayan bir şablon işlevi görür. Genellikle soyut bir temel sınıfta türetilen her türün uygulanması bu türe özeldir. Sınıfı soyut anahtar sözcüğüyle işaretlediniz çünkü bir Publication nesnenin örneğini oluşturmak anlamlı değildi, ancak sınıfı yayınlar için ortak işlevsellik uygulamaları sağlamıştı.

Örneğin, her kapalı iki boyutlu geometrik şekil iki özellik içerir: alan, şeklin iç kapsamı; ve çevre veya şeklin kenarları boyunca mesafe. Ancak bu özelliklerin hesaplanma şekli tamamen belirli şekle bağlıdır. Örneğin, bir dairenin çevresini (veya çevresini) hesaplama formülü, karenin formülünden farklıdır. Shape sınıfı, yöntemleri olan abstract bir abstract sınıftır. Bu, türetilmiş sınıfların aynı işlevselliği paylaştığını gösterir, ancak bu türetilmiş sınıflar bu işlevselliği farklı şekilde uygular.

Aşağıdaki örnek, iki özelliği tanımlayan adlı Shape bir soyut temel sınıf tanımlar: Area ve Perimeter. Sınıfı soyut anahtar sözcükle işaretlemeye ek olarak, her örnek üyesi de soyut anahtar sözcükle işaretlenir. Bu durumda, Shape tam adı yerine türün adını döndürmek için yöntemini de geçersiz kılar Object.ToString . Ve çağıranların türetilmiş herhangi bir sınıfın örneğinin alanını ve çevresini kolayca almasını sağlayan iki statik üye GetAreaGetPerimeterve tanımlar. Türetilmiş bir sınıfın örneğini bu yöntemlerden herhangi birine geçirdiğinizde, çalışma zamanı türetilmiş sınıfın yöntem geçersiz kılmasını çağırır.

public abstract class Shape
{
    public abstract double Area { get; }

    public abstract double Perimeter { get; }

    public override string ToString() => GetType().Name;

    public static double GetArea(Shape shape) => shape.Area;

    public static double GetPerimeter(Shape shape) => shape.Perimeter;
}

Ardından, belirli şekilleri temsil eden bazı sınıfları Shape türetebilirsiniz. Aşağıdaki örnek, Square, Rectangleve Circleüç sınıfını tanımlar. Her biri, alanı ve çevreyi hesaplamak için söz konusu şekil için benzersiz bir formül kullanır. Türetilmiş sınıflardan bazıları, temsil ettikleri şekle özgü ve Circle.Diametergibi Rectangle.Diagonal özellikleri de tanımlar.

using System;

public class Square : Shape
{
    public Square(double length)
    {
        Side = length;
    }

    public double Side { get; }

    public override double Area => Math.Pow(Side, 2);

    public override double Perimeter => Side * 4;

    public double Diagonal => Math.Round(Math.Sqrt(2) * Side, 2);
}

public class Rectangle : Shape
{
    public Rectangle(double length, double width)
    {
        Length = length;
        Width = width;
    }

    public double Length { get; }

    public double Width { get; }

    public override double Area => Length * Width;

    public override double Perimeter => 2 * Length + 2 * Width;

    public bool IsSquare() => Length == Width;

    public double Diagonal => Math.Round(Math.Sqrt(Math.Pow(Length, 2) + Math.Pow(Width, 2)), 2);
}

public class Circle : Shape
{
    public Circle(double radius)
    {
        Radius = radius;
    }

    public override double Area => Math.Round(Math.PI * Math.Pow(Radius, 2), 2);

    public override double Perimeter => Math.Round(Math.PI * 2 * Radius, 2);

    // Define a circumference, since it's the more familiar term.
    public double Circumference => Perimeter;

    public double Radius { get; }

    public double Diameter => Radius * 2;
}

Aşağıdaki örnek, 'den Shapetüretilen nesneleri kullanır. Öğesinden Shape türetilen bir nesne dizisi oluşturur ve dönüş Shape özelliği değerlerini sarmalayan sınıfın Shape statik yöntemlerini çağırır. Çalışma zamanı, türetilmiş türlerin geçersiz kılınan özelliklerinden değerleri alır. Örnek ayrıca dizideki her Shape nesneyi türetilmiş türüne dönüştürür ve atama başarılı olursa, bu alt sınıfının Shapeözelliklerini alır.

using System;

public class Example
{
    public static void Main()
    {
        Shape[] shapes = { new Rectangle(10, 12), new Square(5),
                    new Circle(3) };
        foreach (Shape shape in shapes)
        {
            Console.WriteLine($"{shape}: area, {Shape.GetArea(shape)}; " +
                              $"perimeter, {Shape.GetPerimeter(shape)}");
            if (shape is Rectangle rect)
            {
                Console.WriteLine($"   Is Square: {rect.IsSquare()}, Diagonal: {rect.Diagonal}");
                continue;
            }
            if (shape is Square sq)
            {
                Console.WriteLine($"   Diagonal: {sq.Diagonal}");
                continue;
            }
        }
    }
}
// The example displays the following output:
//         Rectangle: area, 120; perimeter, 44
//            Is Square: False, Diagonal: 15.62
//         Square: area, 25; perimeter, 20
//            Diagonal: 7.07
//         Circle: area, 28.27; perimeter, 18.85