Menu

C# Constructor: Varsayılan, Parametreli, this() ve base() Zincirleme

C# constructor'ları nasıl çalışır: örtük varsayılan constructor ve ne zaman ortadan kalktığı, parametreli ve overload edilmiş constructor'lar, this(...) ve base(...) ile zincirleme, işlerin çalışma sırası, statik ve private constructor'lar ve C# 12 birincil constructor'ları.

Bu sayfada çalıştırılabilir editörler var - düzenle, çalıştır ve sonucu anında gör.

Bir constructor, new ile bir nesne oluşturduğunuzda çalışan koddur. Sınıfla aynı ada sahiptir, dönüş tipi yoktur ve görevi yeni nesneyi herhangi biri kullanmadan önce geçerli bir duruma getirmektir.

Çıktı:

Mug: 8.50
Rejected: price

Constructor negatif bir fiyatı reddettiği için negatif fiyatlı hiçbir Product var olamaz. Bu garanti, alanları dışarıdan ayarlamak yerine constructor yazmanın asıl nedenidir.

Varsayılan constructor ve ne zaman ortadan kalktığı

Bir sınıf hiç constructor bildirmezse derleyici, alan başlatıcılarını çalıştırmaktan başka bir şey yapmayan public, parametresiz bir constructor sağlar. Yalnızca alanları olan bir sınıfta new BankAccount()'un çalışmasının nedeni budur.

Herhangi bir constructor bildirdiğiniz anda o örtük constructor artık üretilmez:

class Product
{
    public string Name;
    public Product(string name) { Name = name; }
}

var p = new Product();   // error CS7036: There is no argument given that corresponds to the required parameter 'name'

Bu, bir serializer, bir ORM ya da generic bir new() kısıtı parametresiz bir constructor'a ihtiyaç duyduğunda insanları şaşırtır. İkisini de istiyorsanız parametresiz olanı kendiniz bildirin:

public Product() { }                       // or
public Product() : this("Unnamed") { }     // delegate to the other one (next section)

Bir constructor public, internal, protected ya da private olabilir. Erişimi, onunla kimin nesne oluşturabileceğine karar verir.

Overloading ve this(...) ile zincirleme

Bir sınıfın farklı parametre listelerine sahip birkaç constructor'ı olabilir. Aynı atamaları her birine kopyalamaktan kaçınmak için onları zincirleyin: : this(...), geçerli gövde çalışmadan önce aynı sınıfın başka bir constructor'ını çağırır.

Çıktı:

new Pizza():
  full constructor: medium, classic, 0
  size-only constructor body
  parameterless constructor body
Result: medium classic with 0 toppings

Zincir önce en eksiksiz constructor'ı çalıştırır ve çağırdığınıza doğru geri çözülür. Asıl işi (doğrulama, atamalar) tek bir constructor'da tutun ve diğerlerinin yalnızca varsayılanları sağlamasına izin verin.

İsteğe bağlı parametreler bir alternatiftir: public Pizza(string size = "medium", string crust = "classic", int toppings = 0) üç çağrıyı da karşılayan tek bir constructor verir. Kısa constructor'ların bir şey hesaplaması gerektiğinde ya da bir varsayılanı değiştirmek çağıranların yeniden derlemesini gerektirmemesi gerektiğinde (isteğe bağlı parametre varsayılanları derleme zamanında çağıran koda kopyalanır) zincirleme hâlâ daha uygundur.

base(...) ile bir temel sınıf constructor'ını çağırmak

Türetilmiş bir sınıf constructor'ları kalıtım almaz. Türetilmiş sınıfın her constructor'ı önce temel sınıfın bir constructor'ını çalıştırmalıdır. Hiçbir şey yazmazsanız derleyici temelin parametresiz constructor'ına bir çağrı ekler; temelin öyle bir constructor'ı yoksa : base(...) ile birini seçmeniz gerekir.

Her şeyin çalışma sırası bir kez görülmeye değer:

Çıktı:

Truck field initializer
Vehicle field initializer
Vehicle constructor body
Truck constructor body
KL-204, 3 axles

Önce alan başlatıcıları çalışır (türetilmiş sınıf temel sınıftan önce), sonra constructor gövdeleri temelden aşağıya doğru çalışır. Yani Truck'ın gövdesi çalıştığında Plate zaten ayarlanmıştır. Bu sıradaki tek tuzak: temel constructor Truck'ın override ettiği bir virtual metodu çağırırsa, override Truck'ın constructor gövdesinden önce çalışır ve Axles'ı hâlâ 0 görür. Constructor'lardan virtual metotlar çağırmaktan kaçının.

Statik constructor'lar

Bir statik constructor bir nesneyi değil tipi başlatır. Parametresi ve erişim belirleyicisi yoktur ve çalışma zamanı onu, tip ilk kullanılmadan hemen önce tam olarak bir kez çağırır.

Çıktı:

Program started
Loading tax table (runs once)
123.00
119.00

Çalışma zamanı statik constructor'ı thread-safe yapar: birkaç thread aynı anda tipe dokunsa bile bir kez çalışır. İstisna fırlatırsa, tipin sonraki her kullanımı süreç boyunca TypeInitializationException fırlatır; bu yüzden onu basit ve başarısız olabilecek G/Ç işlemlerinden uzak tutun.

Constructor ile nesne başlatıcı

Bir nesne başlatıcı, new Pizza("large") { Toppings = 3 }, ikinci bir constructor değildir. Derleyici onu "constructor'ı çalıştır, sonra bu üyeleri ata"ya çevirir. Her birini iyi olduğu iş için kullanın:

  • Constructor parametreleri, nesnenin onlarsız geçerli olamayacağı değerler için. Her çağıran onları vermek zorundadır ve constructor onları kontrol edebilir.
  • Başlatıcı, mantıklı varsayılanları olan isteğe bağlı ayarlar için.
var order = new Order(customerId: 42) { Note = "Leave at the door", GiftWrap = true };

C# 11'den beri required işaretli bir property başlatıcıda ayarlanmak zorundadır; bu da başlatıcı sözdizimine constructor'ın garantilerinin bir kısmını verir. Bu, property'ler sayfasında ele alınır.

Private constructor'lar

Bir private constructor, yalnızca sınıfın kendisinin örnek oluşturabileceği anlamına gelir. İki kalıp onu kullanır. Sınıfın oluşturmayı kontrol ettiği ve önbelleğe alınmış bir nesne ya da null döndürebildiği statik bir fabrika metodu ve bir singleton:

Çıktı:

21
100

Sınıfın dışında new Temperature(5m) için derleyici hatası, erişim belirleyicilerin herhangi bir private üye için ürettiği hatayla aynı olan CS0122'dir. Adlandırılmış fabrika metotları gerçek bir kısıtlamayı çözer: iki constructor ikisi birden tek bir decimal alamaz, ama FromCelsius ve FromFahrenheit alabilir. Yalnızca statik üyeleri olan bir sınıf (bir yardımcı sınıf) constructor'ını gizlemek yerine static bildirilmelidir.

Expression-bodied constructor'lar

Gövdesi tek bir deyim olan bir constructor => kullanabilir:

public Product(string name) => Name = name;

Tuple'larla birkaç alanı tek satırda bile atayabilirsiniz: public Point(int x, int y) => (X, Y) = (x, y);.

Birincil constructor'lar (C# 12)

C# 12, bir class ya da struct'ın constructor parametrelerini tipin kendisinde bildirmesine izin verir. Parametreler her üyede kapsamdadır:

public class Customer(string name, int id)
{
    public string Name { get; } = name;          // copy into a property
    public string Label => $"#{id} {Name}";      // or read a parameter directly

    public Customer(string name) : this(name, 0) { }   // other constructors must chain to it
}

Record'lardan iki fark insanları şaşırtır. Bir sınıfın birincil constructor parametreleri public property'lere dönüşmez; onları kendiniz dışa açarsınız. Ve bir üyenin içinde kullanılan bir parametre, değiştirilebilir kalan gizli bir alana yakalanır, bu yüzden bir metodun içinde name = "x"; derlenir. Birincil constructor'lar en çok, parametrelerin sınıfın yalnızca çağırdığı servisler olduğu dependency injection'da yerindedir:

public class OrderService(IOrderRepository repo, ILogger<OrderService> log)
{
    public Order Get(int id) => repo.Find(id);
}

Yaygın hatalar

  • Parametresiz constructor'ı kaybetmek. Parametreli bir constructor eklemek örtük olanı kaldırır (her new X()'te CS7036).
  • Temel sınıfın parametresiz constructor'ı yokken : base(...)'i unutmak. Derleyici örtük çağrıyı ekleyemez ve temel constructor'ın zorunlu parametresi için argüman olmadığını bildirir.
  • Bir constructor'da virtual metotlar çağırmak. Override, türetilmiş constructor'ın gövdesinden önce çalışır.
  • Bir constructor'da ağır iş. Ağ çağrıları, dosya okumaları ya da yavaş herhangi bir şey nesneleri pahalı ve istisnaları ele alması zor hale getirir. Bu iş için statik bir fabrika metodu ya da async bir başlatma metodu kullanın.
  • Bir dönüş tipi yazmak. public void Product() Product adlı sıradan bir metottur ve derleyici onu reddeder, çünkü bir üye çevreleyen tipiyle aynı ada sahip olamaz (CS0542).

Sıkça Sorulan Sorular

C#'ta constructor nedir?

Constructor, bir nesne new ile oluşturulduğunda çalışan özel bir metottur. Sınıfla aynı ada sahiptir ve dönüş tipi yoktur: public Product(string name) { Name = name; }. Görevi yeni nesneyi geçerli bir durumda bırakmaktır; tipik olarak alanları parametrelerinden atar ve hatalı girdiyi reddeder.

C# otomatik olarak varsayılan constructor oluşturur mu?

Yalnızca sınıf hiç constructor bildirmediğinde. O zaman derleyici her alanı başlatıcısında ya da varsayılan değerinde bırakan public, parametresiz bir constructor ekler. Herhangi bir constructor yazdığınız anda, örneğin bir ad alan bir tane, örtük olan ortadan kalkar ve new Product() derlenmez (CS7036 hatası). Hâlâ ihtiyacınız varsa public Product() { }'u kendiniz bildirin.

C#'ta bir constructor'dan başka bir constructor nasıl çağrılır?

Constructor'ın parametre listesinden sonra : this(...) kullanın: public Product(string name) : this(name, 0m) { }. Önce hedef constructor çalışır, sonra çağırdığınızın gövdesi. Temel sınıfın bir constructor'ını çağırmak için aynı şekilde : base(...) kullanın.

C#'ta statik constructor nedir?

static işaretli, parametresiz ve erişim belirleyicisiz, ilk örnek oluşturulmadan ya da ilk statik üye kullanılmadan önce tip başına bir kez çalışan bir constructor'dır. Tek satırlık bir başlatıcıdan fazlasını gerektiren statik alanları başlatmak için kullanılır. Onu kendiniz çağıramazsınız ve istisna fırlatırsa tip programın geri kalanında kullanılamaz hale gelir (TypeInitializationException).

Constructor mı kullanmalıyım, nesne başlatıcı mı?

Nesnenin onlarsız geçerli olamayacağı değerler için constructor parametreleri kullanın, çünkü derleyici her çağıranı onları vermeye zorlar ve constructor onları kontrol edebilir. İsteğe bağlı ayarlar için bir nesne başlatıcı (new Product("Mug") { Color = "blue" }) kullanın. Başlatıcı constructor bittikten sonra çalışır.

C# 12'deki birincil constructor'lar nedir?

Sınıf bildiriminin kendisinde yazılan ve sınıfın her üyesinin erişebildiği parametrelerdir: class Customer(string name, int id) { ... }. Bir record'un konumsal parametrelerinin aksine public property'lere dönüşmezler: onları public string Name => name; ya da public string Name { get; } = name; ile açıkça dışa açın.

Coddy programming languages illustration

Coddy ile kodlamayı öğren

BAŞLA