لماذا لا يستطيع الفصل توسيع فئته المتداخلة في C#؟

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

  •  06-07-2019
  •  | 
  •  

سؤال

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

public class A : A.B
{
    public class B { }
}

الذي يولد هذا الخطأ من المترجم:

تبعية الطبقة الأساسية الدائرية التي تنطوي على "A" و "AB"

لقد اعتقدت دائمًا أن الفصل المتداخل يتصرف تمامًا مثل الفصل العادي باستثناء وجود قواعد خاصة تتعلق بالوصول إلى الأعضاء الخاصين في الفصل الخارجي، ولكن أعتقد أن هناك بعض الميراث الضمني الذي يحدث بين الفئتين؟

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

المحلول

ليس هناك وراثة ضمنية بقدر ما أستطيع أن أقول.كنت أتوقع أن يكون هذا جيدًا - على الرغم من أنني أستطيع أن أتخيل الغرابة إذا كان A وB عامان.

تم تحديده في القسم 10.1.4 من المواصفات:

عندما يستمد الفئة B من الفئة A ، يكون خطأ في وقت الترجمة ليعتمد على B.يعتمد الفصل بشكل مباشر على فئة القاعدة المباشرة (إن وجد) و يعتمد بشكل مباشر على الفصل الذي يتم فيه التداخل على الفور (لو اي).بالنظر إلى هذا التعريف ، فإن المجموعة الكاملة من الفئات التي يعتمد عليها الفصل هي الإغلاق التعريفي للعلاقة مباشرة على العلاقة.

لقد أبرزت القسم ذي الصلة.

وهذا يفسر سبب رفض المترجم لها، ولكن ليس سبب حظر اللغة لها.أتساءل عما إذا كان هناك قيود CLI ...

يحرر:حسنًا، لقد تلقيت ردًا من إريك ليبرت.في الأساس، سيكون ذلك ممكنًا من الناحية الفنية (لا يوجد شيء في CLI يمنعه)، ولكن:

  • سيكون السماح بذلك أمرًا صعبًا في المترجم، مما يؤدي إلى إبطال الافتراضات الحالية المختلفة حول الطلب والدورات
  • إنه قرار تصميمي غريب جدًا ومن الأسهل حظره بدلاً من دعمه

تمت الإشارة أيضًا في سلسلة رسائل البريد الإلكتروني إلى أن هذا سيجعل هذا النوع من الأشياء صالحًا:

A.B x = new A.B.B.B.B.B.B.B.B.B.B.B.B();

...ولكن هذا سيكون بالفعل (كما لاحظ Tinister) صالحًا إذا كان B مشتقًا من A.

التعشيش + الميراث = الشذوذ...

نصائح أخرى

وهذه ليست C # شيء بقدر ما هو الشيء مترجم. واحدة من وظائف مترجم هو وضع فئة في الذاكرة، وهذا هو حفنة من أنواع البيانات الأساسية، مؤشرات، مؤشرات الدالة والفئات الأخرى.

لا يمكن بناء تخطيط لفئة A حتى يعرف ماذا تخطيط الفئة B هو. لا يمكن أن تعرف ما هو تخطيط من الدرجة B حتى الانتهاء من تخطيط الفئة A. الاعتماد الدائرية.

وأعتقد أن يعني تداخل لتمثيل أن نوع متداخلة هو <م> جزءا من تعريف من نوع التعشيش. مع هذا التفسير، والحد من المنطقي لأن في ذلك الوقت المترجم يضرب تعريف A، لم يتم تعريف A.B بعد، وحتى في نهاية A، ويعرف ذلك بالفعل من حيث A.B.

وردا على تساؤلات حول ما كان يحاول القيام به:

وأساسا، أردت أن تخلق فئة التي كان على علاقة مع تكوين نفسها، ولكن لم أكن أريد أن يكون الكائن الواردة إلى تحتوي على كائنات أخرى، وبالتالي إنشاء سلسلة مع العديد من "A ديه واحد لديه واحد A العلاقات ديه واحد ولها واحد ... ". لذلك كان فكرتي في ذلك الوقت أن تفعل شيئا من هذا القبيل:

public class A : A.AA
{
    public class AA
    {
        // All of the class's logic
    }

    private AA _containedObject;
}

في الوقت الذي بدا بقعة جميلة ولكن في وقت لاحق لست متأكدا من ذلك ...

وكنت قد بالتفتيش من خلال جوجل ولم تجد أي مناقشة جيدة على ذلك حتى اعتقدت أن وظيفة هنا.

ولكن، في تصريحات ل<لأ href = "http://blogs.msdn.com/ericlippert/archive/2008/09/26/preventing-third-party-derivation-part-one.aspx" يختلط = "noreferrer نوفولو"> آخر في مدونة اريك ليبرت في انه يعطي أمثلة من فئة تنفيذ واجهة المتداخلة فضلا عن الطبقة تنفيذ واجهة عامة مع فئة متداخلة كوسيطة نوع (الذي لا تجميع وانه استدعاء "علة" في المجمع الحالي). كل من هذه الأمثلة تهم واجهات لذلك أنا أتساءل عما اذا كان هناك بعض القواعد الخاصة مع الطبقات المتداخلة. وعلى ما يبدو هناك.

وكنت قادرا على تجنب هذا (على الأقل مع واجهات) من خلال وراثة من فئة منفصلة تحتوي على واجهات المتداخلة. (في السيناريو بلدي أنا عائد أيضا إشارات إلى هذه الواجهات.)

وبدلا من:

public class MyClass<T1, T2, T3> :
   MyClass<T1, T2, T3>.Interface
where T1 : ...
where T2 : ... 
where T3 : ... {
   public interface Interface { Interface SomeMethod(); }

   Interface Interface.SomeMethod() {
      ...
   }
}

// compile error: Circular base class dependency

وتفعل شيئا من هذا القبيل:

public sealed class MyClassInterfaces<T1, T2, T3>
where T1 : ...
where T2 : ... 
where T3 : ... {
   public interface Interface { Interface SomeMethod(); }
}

sealed class MyClass<T1, T2, T3> :
   MyClassInterfaces<T1, T2, T3>.Interface
where T1 : ...
where T2 : ... 
where T3 : ... {
   MyClassInterfaces<T1, T2, T3>.Interface
   MyClassInterfaces<T1, T2, T3>.Interface.SomeMethod() {
      ...
   }
}

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

public abstract class MyClassInterfaces<T1, T2, T3>
where T1 : ...
where T2 : ... 
where T3 : ... {
   public interface Interface { Interface SomeMethod(); }
}

sealed class MyClass<T1, T2, T3> :
   MyClassInterfaces<T1, T2, T3>,
   MyClassInterfaces<T1, T2, T3>.Interface
where T1 : ...
where T2 : ... 
where T3 : ... {
   Interface Interface.SomeMethod() {
      ...
   }
}

وهذا لا معنى له بالنسبة لي ... أنت تحاول تمديد شيء لا وجود له! الفئة B لا توجد إلا في نطاق فئة A و بسبب هذا أعتقد أن هناك نوعا من الميراث.

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