سؤال

ويطبع البرنامج التالي

A:C(A,B)
B:C(A,B)

و(كما يجب)

public interface I
{
    string A();
}

public class C : I
{
    public string A()
    {
        return "A";
    }

    public string B()
    {
        return "B";
    }
}

public class A
{
    public virtual void Print(C c)
    {
        Console.WriteLine("A:C(" + c.A() + "," + c.B() + ")");
    }
}

public class B : A
{
    public new void Print(C c)
    {
        Console.WriteLine("B:C(" + c.A() + "," + c.B() + ")");
    }

    public void Print(I i)
    {
        Console.WriteLine("B:I(" + i.A() + ")");
    }
}

class Program
{
    public static void Main(string[] args)
    {
        A a = new A();
        B b = new B();
        C c = new C();
        a.Print(c);
        b.Print(c);
    }
}

ولكن، إذا قمت بتغيير الكلمة 'الجديدة' إلى 'تجاوز' في الفئة باء مثل ذلك:

    public override void Print(C c)

وكل من برنامج المفاجئ يبدأ الطباعة:

A:C(A,B)
B:I(A)

لماذا؟

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

المحلول

وهذا هو أن تفعل مع كيفية طرق طاقتها يتم حلها.

وفعال (المبسطة إلى حد ما)، ومترجم تبدو لأول مرة في نوع المعلنة للتعبير (B) في هذه القضية وبالبحث عن الطرق المرشحة <م> والتي يعلن عنها للمرة الأولى في هذا النوع . إذا كان هناك أي الأساليب التي تتناسب (أي حيث كل الحجج يمكن تحويلها إلى أنواع المعلمة طريقة ل) ثم <م> لا ننظر في أي نوع من أنواع الأم. وهذا يعني أن أساليب متجاوزة، حيث الإعلان الأولي هو في نوع الأم، لا تحصل على نظرة في ما إذا كان هناك أي "أعلن حديثا" الأساليب المناسبة في نوع المشتقة.

وإليك مثال أبسط قليلا:

using System;

class Base
{
    public virtual void Foo(int x)
    {
        Console.WriteLine("Base.Foo(int)");
    }
}

class Derived : Base
{
    public override void Foo(int x)
    {
        Console.WriteLine("Derived.Foo(int)");
    }

    public void Foo(double d)
    {
        Console.WriteLine("Derived.Foo(double)");
    }
}

class Test
{
    static void Main()
    {
        Derived d = new Derived();
        d.Foo(10);
    }
}

وهذا يطبع Derived.Foo(double) - على الرغم من أن المترجم يعرف أن هناك طريقة مطابقة مع معلمة من نوع int، والحجة هي اكتب int، وتحويل من int إلى int هو "أفضل" من التحويل من int إلى double، حقيقة أنه ليس هناك سوى طريقة Foo(double) هو في الأصل <م> أعلن في Derived يعني مترجم يتجاهل Foo(int).

وهذا هو المدهش للغاية IMO. أستطيع أن أرى لماذا سيكون الحال إذا Derived لم تتجاوز Foo - إدخال خلاف ذلك أكثر تحديدا، طريقة جديدة في الفئة الأساسية يمكن تغيير سلوك غير متوقع - ولكن Derived بوضوح هنا يعرف حول Base.Foo(int) كما انها تجاوز ذلك. هذا هو واحد من (القليلة نسبيا) النقاط التي أعتقد جعلت C # المصممين قرار خاطئ.

نصائح أخرى

وطيب، لذلك

    public new void Print(C c)
    {
        Console.WriteLine("B:C(" + c.A() + "," + c.B() + ")");
    }

    public void Print(I i)
    {
        Console.WriteLine("B:I(" + i.A() + ")");
    }

وهذا يعلن طريقة جديدة للطباعة. الآن لB يرث من A، الذي تتصل به simly الطريقة الجديدة مرتين. عند overide طريقة، وهذا تغيير ثم توقيع الأسلوب عند استدعاء لA، ولكن عند استدعاء توقيع B، فعليها توقيع الأسلوب الخاص بها.

ولست متأكدا إذا أنا موضحا سؤال واضح ولكن جيدة.

وباستخدام الجديد:

وألف وباء الحصول على نفس تنفيذ أسلوب الطباعة.

وباستخدام تجاوز:

وA لديه توقيع الأسلوب مختلفة إلى B كما، لم تكن قد غيرت توقيع الأسلوب في B فقط في A.

وباستخدام الجديد هو في الأساس يتجاهل هذا:

    public void Print(I i)
    {
        Console.WriteLine("B:I(" + i.A() + ")");
    }

وكان هذا سؤال كبير.
كل الأجوبة يمكن العثور عليها هنا: http://msdn.microsoft.com/en-us /library/6fawty39(VS.80).aspx

ووجوهر ذلك هو:

<اقتباس فقرة>   

... في C # المترجم أولا سيحاول جعل   الدعوة متوافقة مع الإصدارات   من [functionName] أعلن أصلا على   [فئة مشتقة]. طرق تجاوز ليست   تعتبر أعلن على فئة،   هم تطبيقات جديدة ل   أعلن الأسلوب على الفئة الأساسية. فقط   إذا كان # مترجم C لا يمكن أن تتطابق مع   استدعاء الأسلوب إلى أسلوب الأصلي على   [فئة مشتقة] فإنه يحاول تطابق الدعوة   إلى أسلوب متجاوزة مع نفسه   اسم والمعلمات المتوافقة.

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

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

وهذا هو على الأقل بقدر ما هو سؤال حول كيف طريقة <م> الحمولة الزائدة يعمل في C #. أعتقد أنك قد سلط الضوء على حالة مثيرة للاهتمام هنا ...

في الحالة الأولى (باستخدام الكلمة new على طريقة)، ومترجم يقرر استخدام الزائد طريقة Print مع المعلمة من نوع C لأنها نوع ما يعادل بالضبط إلى أن المعلمة مرت (أي لا التحويل الضمني هو حاجة لها) في حين أن التحويل الضمني إلى واجهة ستكون هناك حاجة I إذا كان المترجم لاختيار طريقة Print أن يأخذ حجة من نوع I -. وبعبارة أخرى، فإنه يختار أكثر "وضوحا" طريقة الزائد

في الحالة الثانية (باستخدام الكلمة override على طريقة)، يقرر مترجم لاستخدام الزائد للPrint مع المعلمة من النوع الأول لأنه على الرغم كنت تجاوز الزائد طريقة Print(C c) في فئة B، يتم تعريفه بشكل فعال في الفئة الأصل A، مما يجعل الزائد طريقة Print(I i) في الواقع الزائد على مستوى أعلى، وبالتالي الأكثر مباشرة، أي أول واحد يجد المترجم.

ونأمل أن هذا سوف تساعدك على فهم. اسمحوا لي أن أعرف ما إذا كنت بحاجة إلى clairfy أي نقاط أخرى ...

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

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