Çok biçimlilik

Çok biçimlilik, kapsülleme ve devralma sonrasında nesne odaklı programlama için genellikle üçüncü olarak adlandırılır. Çok biçimlilik, "çoktan şekillendirilmiş" anlamına gelen ve iki ayrı yönü bulunan bir Yunan kelimedir:

  • Çalışma zamanında, türetilmiş bir sınıfın nesneleri Yöntem parametreleri ve koleksiyonlar ya da diziler gibi yerlerde bir temel sınıfın nesneleri olarak kabul edilebilir. Bu çok biçimlilik gerçekleştiğinde, nesnenin bildirildiği tür artık çalışma zamanı türüyle aynı değildir.
  • Temel sınıflar sanal yöntemleri tanımlayabilir ve uygulayabilir ve türetilmiş sınıflar bunları geçersiz kılabilir , bu da kendi tanım ve uygulamasını sağlar. Çalışma zamanında, istemci kodu yöntemi ç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ş sınıfın yönteminin yürütülmesine neden olabilirsiniz.

Sanal yöntemler, ilişkili nesneler gruplarıyla tek bir şekilde çalışmanıza olanak sağlar. Örneğin, bir kullanıcının çizim yüzeyinde çeşitli şekil türlerini oluşturmalarına olanak tanıyan bir çizim uygulamanız olduğunu varsayalım. Kullanıcı tarafından oluşturulacak belirli şekil türlerini derleme zamanında bilemezsiniz. Bununla birlikte, uygulamanın oluşturulan çeşitli şekil türlerini izlemesi gerekir ve Kullanıcı fare eylemlerine yanıt olarak onları güncelleştirmek zorunda olur. Bu sorunu çözmek için iki temel adımda çok biçimlilik kullanabilirsiniz:

  1. Her belirli ş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 herhangi bir türetilmiş sınıfta uygun yöntemi çağırmak için bir sanal yöntem kullanın.

İlk olarak, adlı bir temel sınıf Shape ve, ve gibi türetilmiş sınıflar Rectangle oluşturun Circle Triangle . ShapeSınıfa bir sanal yöntem verin Draw ve sınıfın temsil ettiği belirli şekli çizmek için her türetilmiş sınıfta bunu geçersiz kılın. Bir List<Shape> nesne oluşturun ve bir Circle , Triangle , ve ekleyin Rectangle .

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, listeyi yinelemek ve listedeki her bir nesnede yöntemi çağırmak için bir foreach döngüsü kullanın Draw Shape . Listedeki her nesnenin tanımlanmış bir türü olsa da Shape , çağrılacak çalışma zamanı tü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 whereever 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 dahil olmak üzere tüm türler öğesinden devraldığı için her tür polimorfik olur Object .

Çok biçimlilik genel bakış

Sanal üyeler

Türetilmiş bir sınıf temel sınıftan devraldığında, temel sınıfın tüm yöntemlerini, alanlarını, özelliklerini ve olaylarını alır. Türetilmiş sınıfın Tasarımcısı, Sanal yöntemlerin davranışı için farklı seçeneklere sahiptir:

  • Türetilmiş sınıf, yeni davranışı tanımlayarak temel sınıftaki sanal üyeleri geçersiz kılabilir.
  • Türetilmiş sınıf en yakın temel sınıf yöntemini geçersiz kılmadan devralınabilir, var olan davranışı korur, ancak daha fazla türetilmiş sınıfları yöntemi geçersiz kılacak şekilde etkinleştirir.
  • Türetilmiş sınıf, temel sınıf uygulamalarını gizleyen bu üyelerin sanal olmayan yeni uygulamasını tanımlayabilir.

Türetilmiş bir sınıf, yalnızca temel sınıf üyesi sanal veya soyutolarak bildirilirse bir temel sınıf üyesini geçersiz kılabilir. Türetilmiş üye, metodun sanal çağrıya katılmayı amaçladığı kesin olarak 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 sanal üyeyi geçersiz kıldığında, bu üye, bu sınıfın bir örneği temel sınıfın bir örneği olarak erişildiği zaman bile ç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 bir temel sınıfı genişletmesine imkan tanır. Daha fazla bilgi için bkz. geçersiz kılma ve yeni anahtar sözcüklerle sürüm oluşturma. Bir arabirim, bir yöntemi veya uygulamasının türetilmiş sınıflara ayrılmakta olduğu yöntemler kümesini tanımlamak için başka bir yol sağlar.

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

Türetilmiş sınıfınızın bir temel sınıftaki üye ile aynı ada sahip bir üyeye sahip olmasını istiyorsanız, temel sınıf üyesini gizlemek için New anahtar sözcüğünü kullanabilirsiniz. newAnahtar sözcüğü, değiştirilmekte olan 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ğini bir temel sınıfın örneğine aktararak istemci kodundan erişilebilir. Örnek:

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ı engelle

Sanal üyeler, sanal üye ile ilk olarak tarafından tanımlanan sınıf arasında kaç sınıf bildirildiği dikkate almaksızın sanal olarak kalır. Sınıfı A bir sanal üye bildiriyorsa ve sınıfından türetilmiş sınıf ve sınıfından türetiliyor, sınıf B A C B C sanal üyeyi devralır ve sınıfın B Bu üye için bir geçersiz kılma olarak bildirilip bildirilmediğine bakılmaksızın onu 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, bir geçersiz kılma korumalıolarak bildirerek sanal devralmayı durdurabilir. Devralma durdurulduğunda, sealed override sınıf üye bildiriminde anahtar sözcükten önce anahtar sözcüğü koyulması gerekir. Aşağıdaki kod bir örnek sağlar:

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

Önceki örnekte, yöntemi DoWork öğesinden türetilmiş hiçbir sınıf için artık sanal değildir C . Türlerine C veya türüne saçılması durumunda bile, örnekleri için hala sanal olur B A . Aşağıdaki örnekte gösterildiği gibi, korumalı Yöntemler, anahtar sözcüğü kullanılarak türetilmiş sınıflar tarafından değiştirilebilir new :

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

Bu durumda, DoWork D türünde bir değişken kullanılarak çağrılırsa D , yeni DoWork çağırılır. Bir C B örneğine erişmek için, veya türünde bir değişken A kullanılırsa D , öğesine yapılan bir çağrı, DoWork sanal devralma kurallarını izleyerek bu çağrıları sınıfının uygulamasına yönlendirme DoWork C işlemini kullanır.

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

Bir yöntemi veya özelliği değiştirilmiş veya geçersiz kılan türetilmiş bir sınıf, anahtar sözcüğünü kullanarak temel sınıftaki yönteme veya özelliğe erişmeye devam edebilir base . 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 base kendi uygulamalarında bu üyenin temel sınıf uygulamasını çağırmak için kullanılması ö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 odaklanmalarını sağlar. Temel sınıf uygulama çağrılıp, davranışını temel sınıfın davranışıyla uyumlu hale getirmek için türetilmiş sınıfa kadar olur.