C# - استخدام الكلمات الرئيسية افتراضي + تجاوز مقابل.جديد

StackOverflow https://stackoverflow.com/questions/159978

سؤال

ما هي الاختلافات بين الإعلان عن طريقة في النوع الأساسي "virtual"ثم تجاوزه في نوع تابع باستخدام"override"الكلمة الرئيسية بدلاً من مجرد استخدام"new"الكلمة الأساسية عند الإعلان عن طريقة المطابقة في النوع الفرعي؟

هل كانت مفيدة؟

المحلول

لا يتم تجاوز الكلمة الأساسية "جديدة"، فهي تشير إلى طريقة جديدة لا علاقة لها بطريقة الفئة الأساسية.

public class Foo
{
     public bool DoSomething() { return false; }
}

public class Bar : Foo
{
     public new bool DoSomething() { return true; }
}

public class Test
{
    public static void Main ()
    {
        Foo test = new Bar ();
        Console.WriteLine (test.DoSomething ());
    }
}

هذا يطبع خطأ، إذا استخدمت التجاوز لكان قد طبع صحيحًا.

(الرمز الأساسي مأخوذ من جوزيف ديجل)

لذلك، إذا كنت تفعل تعدد الأشكال الحقيقي لك ينبغي دائما تجاوز.المكان الوحيد الذي تحتاج فيه إلى استخدام "جديد" هو عندما لا تكون الطريقة مرتبطة بأي شكل من الأشكال بإصدار الفئة الأساسية.

نصائح أخرى

أجد دائمًا أشياء مثل هذه يسهل فهمها باستخدام الصور:

مرة أخرى، بأخذ كود جوزيف ديجل،

public class Foo
{
     public /*virtual*/ bool DoSomething() { return false; }
}

public class Bar : Foo
{
     public /*override or new*/ bool DoSomething() { return true; }
}

إذا قمت بعد ذلك باستدعاء الرمز مثل هذا:

Foo a = new Bar();
a.DoSomething();

ملحوظة:الشيء المهم هو أن الجسم الذي لدينا هو في الواقع أ Bar, ، لكنا كذلك تخزينه في متغير من النوع Foo (وهذا يشبه صب ذلك)

ثم ستكون النتيجة على النحو التالي، اعتمادا على ما إذا كنت قد استخدمت virtual/override أو new عندما تعلن عن الفصول الدراسية الخاصة بك.

Virtual/Override explanation image

وفيما يلي بعض التعليمات البرمجية لفهم الفرق في سلوك الطرق الافتراضية وغير الافتراضية:

class A
{
    public void foo()
    {
        Console.WriteLine("A::foo()");
    }
    public virtual void bar()
    {
        Console.WriteLine("A::bar()");
    }
}

class B : A
{
    public new void foo()
    {
        Console.WriteLine("B::foo()");
    }
    public override void bar()
    {
        Console.WriteLine("B::bar()");
    }
}

class Program
{
    static int Main(string[] args)
    {
        B b = new B();
        A a = b;
        a.foo(); // Prints A::foo
        b.foo(); // Prints B::foo
        a.bar(); // Prints B::bar
        b.bar(); // Prints B::bar
        return 0;
    }
}

والكلمة new يخلق في الواقع عضوا جديدا تماما ما هو موجود فقط في ذلك نوع معين.

وعلى سبيل المثال

public class Foo
{
     public bool DoSomething() { return false; }
}

public class Bar : Foo
{
     public new bool DoSomething() { return true; }
}

وهذه الطريقة موجودة على كلا النوعين. عند استخدام انعكاس والحصول على أعضاء نوع Bar، وسوف تجد فعلا 2 أساليب دعا DoSomething() التي تبدو بالضبط نفس الشيء. باستخدام new قمت بإخفاء بفعالية تنفيذ في الفئة الأساسية، بحيث عندما تستمد فئات من Bar (في بلدي على سبيل المثال) استدعاء الأسلوب إلى base.DoSomething() يذهب إلى Bar وليس Foo.

الظاهري / التجاوز يخبر المترجم أن الطريقتين مرتبطتان وأنه في بعض الحالات عندما تعتقد أنك تتصل بالطريقة الأولى (الافتراضية)، فمن الصحيح بالفعل استدعاء الطريقة الثانية (المتجاوزة) بدلاً من ذلك.هذا هو أساس تعدد الأشكال.

(new SubClass() as BaseClass).VirtualFoo()

سيتم استدعاء أسلوب VirtualFoo() الذي تم تجاوزه في الفئة الفرعية.

جديد يخبر المترجم أنك تقوم بإضافة طريقة إلى فئة مشتقة بنفس اسم الطريقة الموجودة في الفئة الأساسية، لكن ليس لديهما علاقة ببعضهما البعض.

(new SubClass() as BaseClass).NewBar()

سيتم استدعاء طريقة NewBar () الخاصة بـ BaseClass، بينما:

(new SubClass()).NewBar()

سيتم استدعاء أسلوب NewBar () الخاص بـ SubClass.

وراء مجرد التفاصيل التقنية، وأعتقد أن استخدام الظاهري / تجاوز يتصل الكثير من المعلومات الدلالي على التصميم. عندما تقوم بتعريف طريقة الظاهري، فإنك تشير إلى تتوقع أن الفصول تنفيذ قد ترغب أن تقدم تطبيقات غير الافتراضية الخاصة بهم. حذف هذا في فئة أساسية، وبالمثل، يعلن توقع أن يجب الأسلوب الافتراضي ليكفي لجميع الطبقات المنفذة. وبالمثل، يمكن للمرء استخدام الإعلانات مجردة لإجبار الطبقات المنفذة أن تقدم التنفيذ الخاصة بها. مرة أخرى، وأعتقد أن هذا يتصل الكثير عن كيف يتوقع مبرمج رمز لاستخدامها. لو كنت أكتب كل من القاعدة وتنفيذ الطبقات وجدت نفسي باستخدام الجديد فما استقاموا لكم فاستقيموا إعادة التفكير بجدية في قرار عدم جعل طريقة الظاهري في الأصل وتعلن هدفي على وجه التحديد.

الفرق بين الكلمة الرئيسية للتجاوز والكلمة الرئيسية الجديدة هو أن الأولى تقوم بتجاوز الطريقة والأحدث تقوم بإخفاء الطريقة.

راجع الروابط التالية للمزيد من المعلومات...

MSDN و آخر

  • new الكلمة الرئيسية للاختباء.- يعني أنك تخفي طريقتك في وقت التشغيل.سوف يعتمد الإخراج على طريقة الفئة الأساسية.
  • override للتجاوز.- يعني أنك تستدعي طريقة الفئة المشتقة الخاصة بك مع مرجع الفئة الأساسية.سوف يعتمد الإخراج على طريقة الفئة المشتقة.

نسختي من الشرح تأتي من استخدام ملكيات للمساعدة في فهم الاختلافات.

override بسيطة بما فيه الكفاية، أليس كذلك؟النوع الأساسي يتجاوز الوالدين.

new ربما يكون مضللاً (بالنسبة لي كان).من الأسهل فهم الخصائص:

public class Foo
{
    public bool GetSomething => false;
}

public class Bar : Foo
{
    public new bool GetSomething => true;
}

public static void Main(string[] args)
{
    Foo foo = new Bar();
    Console.WriteLine(foo.GetSomething);

    Bar bar = new Bar();
    Console.WriteLine(bar.GetSomething);
}

باستخدام مصحح الأخطاء يمكنك ملاحظة ذلك Foo foo لديه 2 GetSomething الخصائص، حيث أنها تحتوي في الواقع على نسختين من الخاصية، Foo'رمل Bar's، ولمعرفة أي منها يجب استخدامه، يقوم c# "باختيار" الخاصية للنوع الحالي.

إذا كنت ترغب في استخدام إصدار الشريط، كنت قد استخدمت التجاوز أو الاستخدام Foo foo بدلاً من.

Bar bar عنده فقط 1, كما يريد تماما جديد السلوك ل GetSomething.

لا تدل على الأسلوب مع أي شيء يعني: ربط هذه الطريقة باستخدام نوع الترجمة للكائن، وليس وقت التشغيل نوع (ثابت ملزم).

ووسم طريقة مع virtual يعني: ربط هذه الطريقة باستخدام التشغيل نوع الكائن، وليس تجميع نوع الساعة (دينامية ملزمة).

ووسم طريقة virtual الفئة الأساسية مع override في فئة مشتقة يعني: هذا هو الأسلوب على الالتزام باستخدام التشغيل نوع الكائن (دينامية ملزمة).

ووسم طريقة الفئة الأساسية virtual مع new في فئة مشتقة يعني: هذا هو الأسلوب الجديد، وهذا لا علاقة له واحد يحمل نفس الاسم في الفئة الأساسية، وينبغي أن تكون ملزمة باستخدام نوع وقت الترجمة الكائن (ثابت ملزم ).

وليس بمناسبة طريقة virtual الفئة الأساسية في فئة مشتقة يعني: ويتميز هذا الأسلوب كما new (ثابت ملزم).

ووسم على abstract طريقة يعني: هذا الأسلوب هو ظاهري، لكنني لن يعلن الجسم لذلك وفئتها أيضا مجردة (دينامية ملزمة).

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top