Çok biçimlilik

Polimorfizm genellikle kapsülleme ve devralma sonrasında nesne odaklı programlamanın üçüncü yapı taşı olarak adlandırılır. Polimorfizm, "çok şekilli" anlamına gelen bir Yunanca kelimedir ve iki farklı yönü vardır:

  • Çalışma zamanında türetilmiş bir sınıfın nesneleri, yöntem parametreleri, koleksiyonlar veya diziler gibi yerlerde temel sınıfın nesneleri olarak kabul edilebilir. Bu çok biçimlilik oluştuğunda, nesnenin bildirilen türü artık çalışma zamanı türüyle aynı değildir.
  • Temel sınıflar sanalyöntemleri tanımlayıp uygulayabilir ve türetilmiş sınıflar bunları geçersiz kılabilir, yani kendi tanımlarını ve uygulamalarını sağlarlar. Çalışma zamanında, istemci kodu yöntemini çağırdığında, CLR nesnenin çalışma zamanı türünü arar ve sanal yöntemin geçersiz kılmasını çağırır. Kaynak kodunuzda bir temel sınıfta bir yöntemi çağırabilir ve türetilmiş bir sınıfın yönteminin sürümünün yürütülmesine neden olabilirsiniz.

Sanal yöntemler, ilgili nesne gruplarıyla tekdüzen bir şekilde çalışmanızı sağlar. Örneğin, kullanıcının çizim yüzeyinde çeşitli şekiller oluşturmasına olanak tanıyan bir çizim uygulamanız olduğunu varsayalım. Derleme zamanında kullanıcının hangi şekil türlerini oluşturacağını bilmezsiniz. Ancak, uygulamanın oluşturulan tüm çeşitli şekil türlerini izlemesi ve bunları kullanıcı fare eylemlerine yanıt olarak güncelleştirmesi gerekir. Bu sorunu çözmek için iki temel adımda çok biçimlilik kullanabilirsiniz:

  1. Her bir şekil sınıfının ortak bir temel sınıftan türetildiği bir sınıf hiyerarşisi oluşturun.
  2. Temel sınıf yöntemine tek bir çağrı aracılığıyla türetilmiş herhangi bir sınıfta uygun yöntemi çağırmak için bir sanal yöntem kullanın.

İlk olarak, adlı Shapebir temel sınıf ve , Circleve Trianglegibi Rectangletüretilmiş sınıflar oluşturun. sınıfına Shape adlı Drawbir sanal yöntem verin ve sınıfın temsil ettiği belirli şekli çizmek için türetilmiş her sınıfta bunu geçersiz kılın. Bir List<Shape> nesne oluşturun ve nesnesine bir Circle, Triangleve Rectangle ekleyin.

public class Shape
{
    // A few example members
    public int X { get; private set; }
    public int Y { get; private set; }
    public int Height { get; set; }
    public int Width { get; set; }

    // Virtual method
    public virtual void Draw()
    {
        Console.WriteLine("Performing base class drawing tasks");
    }
}

public class Circle : Shape
{
    public override void Draw()
    {
        // Code to draw a circle...
        Console.WriteLine("Drawing a circle");
        base.Draw();
    }
}
public class Rectangle : Shape
{
    public override void Draw()
    {
        // Code to draw a rectangle...
        Console.WriteLine("Drawing a rectangle");
        base.Draw();
    }
}
public class Triangle : Shape
{
    public override void Draw()
    {
        // Code to draw a triangle...
        Console.WriteLine("Drawing a triangle");
        base.Draw();
    }
}

Çizim yüzeyini güncelleştirmek için foreach döngüsünü kullanarak listede yineleme yapın ve listedeki her Shape nesnede yöntemini çağırınDraw. Listedeki her nesnenin Shapebildirilen türü olsa da, çağrılacak olan çalışma zamanı türüdür (türetilmiş her sınıfta yöntemin geçersiz kılınan sürümü).

// Polymorphism at work #1: a Rectangle, Triangle and Circle
// can all be used wherever a Shape is expected. No cast is
// required because an implicit conversion exists from a derived
// class to its base class.
var shapes = new List<Shape>
{
    new Rectangle(),
    new Triangle(),
    new Circle()
};

// Polymorphism at work #2: the virtual method Draw is
// invoked on each of the derived classes, not the base class.
foreach (var shape in shapes)
{
    shape.Draw();
}
/* Output:
    Drawing a rectangle
    Performing base class drawing tasks
    Drawing a triangle
    Performing base class drawing tasks
    Drawing a circle
    Performing base class drawing tasks
*/

C# dilinde, kullanıcı tanımlı türler de dahil olmak üzere tüm türler öğesinden Objectdevraldığından her tür çok biçimli olur.

Çok biçimliliğe genel bakış

Sanal üyeler

Türetilmiş bir sınıf temel sınıftan devraldığında, temel sınıfın tüm üyelerini içerir. Temel sınıfta bildirilen tüm davranış türetilmiş sınıfın bir parçasıdır. Bu, türetilmiş sınıfın nesnelerinin temel sınıfın nesneleri olarak kabul edilmesine olanak tanır. Access değiştiricileri (public, protectedprivate vb.), bu üyelerin türetilmiş sınıf uygulamasından erişilebilir olup olmadığını belirler. Sanal yöntemler, tasarımcıya türetilmiş sınıfın davranışı için farklı seçenekler sunar:

  • Türetilmiş sınıf, temel sınıftaki sanal üyeleri geçersiz kılabilir ve yeni davranış tanımlanabilir.
  • Türetilmiş sınıf, mevcut davranışı koruyarak ancak yöntemi geçersiz kılmak için daha fazla türetilmiş sınıfları etkinleştirerek geçersiz kılmadan en yakın temel sınıf yöntemini devralabilir.
  • Türetilmiş sınıf, temel sınıf uygulamalarını gizleyen üyelerin sanal olmayan yeni uygulamasını tanımlayabilir.

Türetilmiş bir sınıf, yalnızca temel sınıf üyesi sanal veya soyut olarak bildirilirse temel sınıf üyesini geçersiz kılabilir. Türetilmiş üye, yöntemin sanal çağırmaya katılmayı amaçladığını açıkça belirtmek için override anahtar sözcüğünü kullanmalıdır. Aşağıdaki kod bir örnek sağlar:

public class BaseClass
{
    public virtual void DoWork() { }
    public virtual int WorkProperty
    {
        get { return 0; }
    }
}
public class DerivedClass : BaseClass
{
    public override void DoWork() { }
    public override int WorkProperty
    {
        get { return 0; }
    }
}

Alanlar sanal olamaz; yalnızca yöntemler, özellikler, olaylar ve dizin oluşturucular sanal olabilir. Türetilmiş bir sınıf bir sanal üyeyi geçersiz kıldığında, bu sınıfın bir örneğine temel sınıfın bir örneği olarak erişildiğinde bile bu üye çağrılır. Aşağıdaki kod bir örnek sağlar:

DerivedClass B = new DerivedClass();
B.DoWork();  // Calls the new method.

BaseClass A = B;
A.DoWork();  // Also calls the new method.

Sanal yöntemler ve özellikler, türetilmiş sınıfların bir yöntemin temel sınıf uygulamasını kullanmaya gerek kalmadan temel sınıfı genişletmesini sağlar. Daha fazla bilgi için bkz . Geçersiz Kılma ve Yeni Anahtar Sözcüklerle Sürüm Oluşturma. Arabirim, uygulaması türetilmiş sınıflara bırakılan bir yöntem veya yöntem kümesi tanımlamak için başka bir yol sağlar.

Temel sınıf üyelerini yeni üyelerle gizleme

Türetilmiş sınıfınızın bir temel sınıftaki üyeyle aynı ada sahip bir üyeye sahip olmasını istiyorsanız, temel sınıf üyesini gizlemek için yeni anahtar sözcüğünü kullanabilirsiniz. anahtar new sözcüğü, değiştirilen bir sınıf üyesinin dönüş türünden önce konur. Aşağıdaki kod bir örnek sağlar:

public class BaseClass
{
    public void DoWork() { WorkField++; }
    public int WorkField;
    public int WorkProperty
    {
        get { return 0; }
    }
}

public class DerivedClass : BaseClass
{
    public new void DoWork() { WorkField++; }
    public new int WorkField;
    public new int WorkProperty
    {
        get { return 0; }
    }
}

Gizli temel sınıf üyelerine, türetilmiş sınıfın örneği temel sınıfın bir örneğine dönüştürülerek istemci kodundan erişilebilir. Örneğin:

DerivedClass B = new DerivedClass();
B.DoWork();  // Calls the new method.

BaseClass A = (BaseClass)B;
A.DoWork();  // Calls the old method.

Türetilmiş sınıfların sanal üyeleri geçersiz kılmasını engelleme

Sanal üyeler, sanal üye ile ilk olarak bunu bildiren sınıf arasında kaç sınıf bildirildiğine bakılmaksızın sanal kalır. Sınıf A bir sanal üye bildirirse ve sınıfı B öğesinden BAtüretilirse, sınıfı CC sanal üyeyi devralır ve sınıfın bu üye için geçersiz kılma bildirip bildirmediğine bakılmaksızın bunu B geçersiz kılabilir. Aşağıdaki kod bir örnek sağlar:

public class A
{
    public virtual void DoWork() { }
}
public class B : A
{
    public override void DoWork() { }
}

Türetilmiş bir sınıf, geçersiz kılmayı korumalı olarak bildirerek sanal devralmayı durdurabilir. Devralmayı durdurmak için anahtar sözcüğün sealed sınıf üyesi bildiriminde anahtar sözcüğün override önüne koyulması gerekir. Aşağıdaki kod bir örnek sağlar:

public class C : B
{
    public sealed override void DoWork() { }
}

Önceki örnekte yöntemi DoWork artık öğesinden Ctüretilen herhangi bir sınıf için sanal değildir. türüne veya türüne CBAgöre yayında olsalar bile örnekleri için sanaldır. Aşağıdaki örnekte gösterildiği gibi korumalı yöntemler anahtar sözcüğü kullanılarak new türetilmiş sınıflarla değiştirilebilir:

public class D : C
{
    public new void DoWork() { }
}

Bu durumda, türünde Dbir değişken kullanılarak çağrılırsa DoWorkD, yeni DoWork çağrılır. , veya türünde Cbir değişken, örneğine Derişmek için kullanılırsa, DoWork çağrısı sanal devralma kurallarına uyar ve bu çağrıları sınıfında Cuygulamasına DoWork yönlendirirA. B

Türetilmiş sınıflardan temel sınıf sanal üyelerine erişme

Bir yöntemin veya özelliğin yerini alan veya geçersiz kılınan türetilmiş bir sınıf, anahtar sözcüğünü kullanarak temel sınıftaki yönteme veya özelliğe erişmeye base devam edebilir. Aşağıdaki kod bir örnek sağlar:

public class Base
{
    public virtual void DoWork() {/*...*/ }
}
public class Derived : Base
{
    public override void DoWork()
    {
        //Perform Derived's work here
        //...
        // Call DoWork on base class
        base.DoWork();
    }
}

Daha fazla bilgi için bkz . base.

Not

Sanal üyelerin kendi uygulamalarında bu üyenin temel sınıf uygulamasını çağırmak için kullanması base önerilir. Temel sınıf davranışının oluşmasına izin vermek, türetilmiş sınıfın türetilmiş sınıfa özgü davranışı uygulamaya odaklanmasını sağlar. Temel sınıf uygulaması çağrılmazsa, davranışlarını temel sınıfın davranışıyla uyumlu hale getirmek türetilmiş sınıfa kadar olur.