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:
Örneği depolamak için bir dizin oluşturun.
Yeni bir .NET Core projesi oluşturmak için komut istemine dotnet yeni konsol komutunu girin.
Örnekteki kodu kopyalayıp kod düzenleyicinize yapıştırın.
Projenin bağımlılıklarını yüklemek veya geri yüklemek için komut satırından dotnet restore komutunu girin.
, ,
dotnet publish
vedotnet pack
gibidotnet test
dotnet run
dotnet build
dotnet new
geri yükleme gerektiren tüm komutlar tarafından örtük olarak çalıştırıldığından, komutunu çalıştırmanızdotnet restore
gerekmez. Örtük geri yüklemeyi devre dışı bırakmak için seçeneğini kullanın--no-restore
.Komutu
dotnet 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.Ö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 C
devralan B
ve temel sınıf türünden devralan türünden A
devralabilir. 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:
Bir sınıfın statik verilerini başlatan statik oluşturucular.
Sınıfının yeni bir örneğini oluşturmak için çağırdığınız örnek oluşturucuları. Her sınıfın kendi oluşturucularını tanımlaması gerekir.
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 veC
öğesindenA
türetilen iç içe geçmiş bir sınıftırA
. ÖzelA._value
alan A.B.'de görünür. Ancak, yöntemindenC.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ıMethod1
bir yöntem tanımlar ve sınıfıB
sınıfındanA
devralır. Örnek daha sonra üzerindeB
bir ö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.Method1
hiç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 SimpleClass
tanı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
publicToString
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 statikEquals(Object, Object)
yöntem ve genel statikReferenceEquals(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 publicGetType
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.ToString
SimpleClass
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 Book
Magazine
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, Publication
günlük, makale vb. her türlü yayını temsil eden bir temel sınıf tanımlayacaksınız. Ayrıca öğesinden Publication
türetilen bir Book
sınıf da tanımlayacaksınız. Örneği, , Journal
, Newspaper
ve Article
gibi Magazine
diğ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 üyelerinPublication
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 eklemenizPublication
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ıPeriodical
olabilir. Bu da , veNewspaper
temel sınıfıdırMagazine
Journal
.Örneğin, küçük bir
Publication
sınıfın hiyerarşisini ve türetilmiş tek bir sınıfınıBook
kullanacaksınız. örneğini kolayca genişleterek veArticle
gibiMagazine
'denPublication
tü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üğüyleabstract
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şaretleyeceksiniz
Publication
.abstract
Herhangi birabstract
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ğinBook
,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 birabstract
yöntemi yoktur, ancak sınıfın kendisidirabstract
.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
sealed
iş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ılarakPublication
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
veType
. Değerler başlangıçta sınıf oluşturucusununPublication
çağrısı tarafından sağlanır.Yayımlamayla ilgili üyeler
İki yöntem ve
Publish
GetPublicationDate
, yayın tarihini ayarlayıp döndürür.Publish
yöntemi çağrıldığında özelpublished
bir bayraktrue
ayarlar ve özel alana bağımsız değişkendatePublished
olarak geçirilen tarihi atar. yöntemi,GetPublicationDate
bayrağıfalse
isepublished
"NYP" dizesini ve isetrue
alanın değerinidatePublished
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ı veCopyrightDate
özelliklerineCopyrightName
atar.Yöntemi geçersiz
ToString
kılmaBir 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ürmekTitle
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.
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ığı Publication
Book
ü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 parametrelerinePublication
karşılık gelir. Üçüncüsü, ortakAuthor
sabit bir özelliğe depolanan yazardır. Bir oluşturucu, otomatik özelliğindeISBN
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 saltISBN
okunur bir özellik. ISBN, oluşturuculardanBook
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 ikiBook
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
veCurrency
. Değerleri birSetPrice
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ındakiBook
kod tarafından ayarlanabilir.SetPrice
veCurrency
özelliklerinin değerleriniPrice
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 ikiBook
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ürmeyitrue
geçersiz kıldığınızdanObject.Equals(Object), özelliği tarafındanISBN
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 Publication
temel sınıfı arasındaki Book
ilişki gösterilmektedir.
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 Publication
Book
bir 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 GetArea
GetPerimeter
ve 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
, Rectangle
ve 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.Diameter
gibi 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 Shape
tü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