كيفية إخفاء خاصية ورث في الفصل دون تعديل الطبقة الموروثة (الطبقة الأساسية)؟

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

سؤال

إذا كان لدي مثال التعليمة البرمجية التالية:

public class ClassBase
{
    public int ID { get; set; }

    public string Name { get; set; }
}

public class ClassA : ClassBase
{
    public int JustNumber { get; set; }

    public ClassA()
    {
        this.ID = 0;
        this.Name = string.Empty;
        this.JustNumber = string.Empty;
    }
}

ماذا علي أن أفعل لإخفاء الممتلكات Name (لا تظهر كعضو في أعضاء الفصل) دون تعديل ClassBase ?

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

المحلول

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

ومع ذلك، عدم الطعن بعيدا عن السؤال المباشر. اذا أنت فعل تريد أن تنقل "القواعد" وتريد الاستمرار في المسار الذي اخترته - إليك كيف يمكنك الذهاب حول هذا الموضوع:

تتمثل الاتفاقية في تنفيذ الممتلكات ولكنها رمي NotimplementedEx عند استدعاء هذه الممتلكات - على الرغم من أنني لا أحب ذلك أيضا. لكن هذا رأيي الشخصي ولا يغير حقيقة أن هذه الاتفاقية لا تزال تقف.

إذا كنت تحاول أن تقول العقار (وأعلن في الفئة الأساسية بأنها افتراضية)، فيمكنك استخدام السمة القديمة عليها:

[Obsolete("This property has been deprecated and should no longer be used.", true)]
public override string Name 
{ 
    get 
    { 
        return base.Name; 
    }
    set
    {
        base.Name = value;
    }
}

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

أو كما ذكرت استخدام notimplementedException:

public override string Name
{
    get
    {
        throw new NotImplementedException();
    }
    set
    {
        throw new NotImplementedException();
    }
}

ومع ذلك، إذا كانت الممتلكات ليس كذلك أعلن Virtual، ثم يمكنك استخدام الكلمة الرئيسية الجديدة لاستبدالها:

public new string Name
{
    get
    {
        throw new NotImplementedException();
    }
    set
    {
        throw new NotImplementedException();
    }
}

لا يزال بإمكانك استخدام السمة القديمة بنفس الطريقة كما لو كانت الطريقة قد تم تجاوزها، أو يمكنك رمي notimplementedException، أيهما تختاره. ربما أستخدم:

[Obsolete("Don't use this", true)]
public override string Name { get; set; }

أو:

[Obsolete("Don't use this", true)]
public new string Name { get; set; }

اعتمادا على ما إذا كان قد تم الإعلان عنها أم لا بشكل افتراضي في الفصل الأساسي.

نصائح أخرى

في حين أن العقار من الناحية الفنية لن تكون مخفية، فإن طريقة واحدة لإثناء استخدامها بقوة هي وضع سمات عليه مثل هذه:

[Browsable(false)]
[Bindable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[EditorBrowsable(EditorBrowsableState.Never)]

هذا هو ما يفعله System.windows.forms للعناصر الضوابط التي تحتوي على خصائص لا تناسبها. ال نص على سبيل المثال، على سبيل المثال، على التحكم، لكن هذا لا معنى له كل فئة يرث من السيطرة. لذلك في Monthcalendar., ، على سبيل المثال، تظهر خاصية النص مثل هذا (لكل مصدر مرجع عبر الإنترنت):

[Browsable(false),
    EditorBrowsable(EditorBrowsableState.Never),
    Bindable(false), 
    DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public override string Text {
    get { return base.Text; }
    set { base.Text = value; }
}
  • استعادة - ما إذا كان العضو يظهر في نافذة الخصائص
  • محرر - ما إذا كان العضو يظهر في المنسدلة الذكية

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

مجرد إخفاءها

 public class ClassBase
{
    public int ID { get; set; }
    public string Name { get; set; }
}
public class ClassA : ClassBase
{
    public int JustNumber { get; set; }
    private new string Name { get { return base.Name; } set { base.Name = value; } }
    public ClassA()
    {
        this.ID = 0;
        this.Name = string.Empty;
        this.JustNumber = 0;
    }
}

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

لماذا الميراث القوة عندما لا تكون ضرورية؟ أعتقد أن الطريقة الصحيحة للقيام بذلك هي القيام به لديه بدل من هو.

public class ClassBase
{
    public int ID { get; set; }

    public string Name { get; set; }
}

public class ClassA
{
    private ClassBase _base;

    public int ID { get { return this._base.ID; } }

    public string JustNumber { get; set; }

    public ClassA()
    {
        this._base = new ClassBase();
        this._base.ID = 0;
        this._base.Name = string.Empty;
        this.JustNumber = string.Empty;
    }
}

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

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

إلى جانب استخدام الجديد لمجرد تجاوز الوظيفة، فإن أحد الأشياء التي لدى Microsoft في Wis Infinite Wis ... .. أوه، أعني أخطاء تعتبر أداة لا جديرة بالاهتمام.

أفضل طريقة لإنجاز هذا الآن هي الميراث متعدد المستويات.

public class classA 
{
}

public class B : A 
{} 

public class C : B 
{} 

فئة B هل تكشف كل عملك وكليتك C عما تحتاج إليه.

لا يمكنك ذلك، هذه هي نقطة الميراث بأكملها: يجب أن تقدم الفرعية الفرعية جميع طرق وخصائص الفئة الأساسية.

يمكنك تغيير التطبيق لرمي استثناء عند استدعاء الخاصية (إذا كان الظاهري) ...

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

لماذا ا؟

التصميم الجيد هو السماح للممتلكات المشتركة بين الفئة الأساسية أن مفهوم معين لديه (افتراضي أو حقيقي). مثال: system.io.stream في C #.

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

القواعد الأساسية التي أستخدمها:

  • تقليل عدد الخصائص والأساليب في الفئة الأساسية. إذا كنت لا تتوقع استخدام بعض الخصائص أو الأساليب في الفصل الذي يرث الفئة الأساسية؛ لا تضعها في baseclass ثم. إذا كنت في تطوير المشروع؛ دائما العودة إلى لوحة الرسم الآن ثم للتحقق من التصميم لأن الأمور تتغير! إعادة تصميم عند الحاجة. عندما يعيش مشروعك تكاليف تغيير الأشياء لاحقا في التصميم سوف ترتفع!

    • إذا كنت تستخدم BaseClass يتم تنفيذها بواسطة Party 3: RD، ففكر في "صعود" مستوى واحد بدلا من "تجاوز" مع "notimplementedException" أو من هذا القبيل. إذا لم يكن هناك مستوى آخر، ففكر في تصميم التعليمات البرمجية من نقطة الصفر.

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

أعلم أن السؤال قديم، ولكن ما يمكنك فعله هو تجاوز postfilterterteries مثل هذا:

 protected override void PostFilterProperties(System.Collections.IDictionary properties)
    {
        properties.Remove("AccessibleDescription");
        properties.Remove("AccessibleName");
        properties.Remove("AccessibleRole");
        properties.Remove("BackgroundImage");
        properties.Remove("BackgroundImageLayout");
        properties.Remove("BorderStyle");
        properties.Remove("Cursor");
        properties.Remove("RightToLeft");
        properties.Remove("UseWaitCursor");
        properties.Remove("AllowDrop");
        properties.Remove("AutoValidate");
        properties.Remove("ContextMenuStrip");
        properties.Remove("Enabled");
        properties.Remove("ImeMode");
        //properties.Remove("TabIndex"); // Don't remove this one or the designer will break
        properties.Remove("TabStop");
        //properties.Remove("Visible");
        properties.Remove("ApplicationSettings");
        properties.Remove("DataBindings");
        properties.Remove("Tag");
        properties.Remove("GenerateMember");
        properties.Remove("Locked");
        //properties.Remove("Modifiers");
        properties.Remove("CausesValidation");
        properties.Remove("Anchor");
        properties.Remove("AutoSize");
        properties.Remove("AutoSizeMode");
        //properties.Remove("Location");
        properties.Remove("Dock");
        properties.Remove("Margin");
        properties.Remove("MaximumSize");
        properties.Remove("MinimumSize");
        properties.Remove("Padding");
        //properties.Remove("Size");
        properties.Remove("DockPadding");
        properties.Remove("AutoScrollMargin");
        properties.Remove("AutoScrollMinSize");
        properties.Remove("AutoScroll");
        properties.Remove("ForeColor");
        //properties.Remove("BackColor");
        properties.Remove("Text");
        //properties.Remove("Font");
    }

يمكنك استخدام Browsable(false)

[Browsable( false )]
public override string Name
{
    get { return base.Name; }
    set { base.Name= value; }
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top