Vă mulțumim pentru susținere

Ascunderea membrilor moșteniți

Căut un mod de a ascunde efectiv membrii moșteniți. Am o bibliotecă de cursuri care moștenesc de la clase comune de bază. Unele dintre cele mai recente clase descendente moștenește proprietăți de dependență care au devenit vestigii și pot fi puțin confuze atunci când folosiți IntelliSense sau folosiți clasele într-un designer vizual.

Aceste clase sunt toate controalele care sunt scrise pentru a fi compilate pentru WPF sau Silverlight 2.0. Știu despre ICustomTypeDescriptor și ICustomPropertyProvider , dar sunt sigur că nu pot fi folosite în Silverlight.

Nu este o chestiune funcțională ca o problemă de utilizare. Ce ar trebui sa fac?

Actualizare

Unele proprietăți pe care mi-ar plăcea să le ascund provin de la strămoșii care nu sunt ai mei și din cauza unui instrument specific pentru care nu lucrez, nu pot face ascunzători cu operatorul new . (Știu, e ridicol)

0
adăugat editat

8 răspunsuri

Deși nu puteți împiedica utilizarea acestor membri moșteniți la cunoștințele mele, ar trebui să le puteți ascunde de la IntelliSense folosind EditorBrowsableAttribute :

Using System.ComponentModel;

[EditorBrowsable(EditorBrowsableState.Never)]
private string MyHiddenString = "Muahahahahahahahaha";

Edit: Just saw this in the documentation comments, which makes it kinda useless for this purpose:

Există o notă proeminentă care afirmă că acest atribut "nu suprimă membrii dintr-o clasă în același ansamblu". Asta este adevărat, dar nu complet. De fapt, atributul nu suprimă membrii dintr-o clasă în aceeași soluție.

0
adăugat

Un lucru potențial pe care îl puteți face este să conțină obiectul mai degrabă decât să se extindă din cealaltă clasă. Acest lucru vă va oferi cea mai mare flexibilitate în ceea ce privește expunerea la ceea ce doriți să expuneți, dar dacă aveți absolut nevoie ca obiectul să fie de acest tip, nu este soluția ideală (cu toate acestea, puteți expune obiectul de la un getter).

Prin urmare:

public class MyClass : BaseClass
{
    // Your stuff here
}

devine:

public class MyClass
{
    private BaseClass baseClass;

    public void ExposeThisMethod()
    {
        baseClass.ExposeThisMethod();
    }
}

Sau:

public class MyClass
{
    private BaseClass baseClass;

    public BaseClass BaseClass
    {
        get
        {
            return baseClass;
        }
    }
}
0
adăugat

Cred că ești cel mai bine cel mai puțin hackist mod este să consideri compoziția, spre deosebire de moștenire.

Sau, puteți crea o interfață care are membrii pe care îi doriți, clasa derivată să implementeze acea interfață și să se programeze pe interfață.

0
adăugat

Ignorați-le ca Michael Suggests de mai sus și pentru a împiedica utilizatorii să folosească metodele suprascrise (sp?), Marcați-le ca depășite:

[Obsolete("These are not supported in this class.", true)]
public override  void dontcallmeanymore()
{
}

Dacă al doilea parm este setat la adevărat, o eroare de compilator va fi generată dacă cineva încearcă să apeleze acea metodă, iar șirul din primul parm este mesajul. Dacă parm2 este falsă, va fi generată o avertizare de compilator.

0
adăugat
Nu puteți să-l sigilați, de asemenea, cu același efect?
adăugat autor James M
@RobertPetz când utilizați învechit, oferă un avertisment, nu o eroare. Mare diferență.
adăugat autor James M
@RobertPetz În mod clar nu mi-ai citit a mea, deși, kudos pentru sarcasmul inutil.
adăugat autor James M
@JamesM nu obselete cu adevărat împiedică membru acces , sigilat împiedică membrii moștenire . Deci, o clasă sigilată nu poate fi derivată din și o metodă sigilată permite altor membri de clasă să fie suprascrise, dar împiedică acest membru să fie suprasolicitat. Semnalat nu împiedică apelarea acelei clase sau a unui membru, în timp ce obselete cu adevărat aruncă o eroare de compilator dacă încercați să o apelați.
adăugat autor Robert Petz
@JamesM uhm ... ați citit chiar răspunsul pe care l-ați comentat în mod literal mai întâi?
adăugat autor Robert Petz
@JamesM lol am făcut, de aceea am răspuns la întrebarea dvs. originală notând de ce sigilare nu a efectuat aceeași sarcină. Apoi ați observat că Obselete dă un avertisment, care este incorect, deoarece al doilea argument al true cauzează mai degrabă o eroare de compilator decât un avertisment - state. Dacă vă înțeleg greșit, salut clarificări. Iată sursă MSDN
adăugat autor Robert Petz

Știu că au fost mai multe răspunsuri la acest lucru și este destul de vechi acum, dar cea mai simplă metodă de a face acest lucru este doar să le declarați ca new private .

Luați în considerare un exemplu în care lucrez în prezent, unde am un API care pune la dispoziție toate metodele dintr-un DLL al unei părți terțe. Trebuie să iau metodele, dar vreau să folosesc o proprietate .Net, în loc de o metodă "getThisValue" și "setThisValue". Deci, construiesc o clasă a doua, moștenesc prima, fac o proprietate care folosește metode de a obține și seta, și apoi suprascrie originalul și pune metode ca private. Acestea sunt încă disponibile pentru oricine dorește să construiască ceva diferit pe ele, dar dacă vor doar să folosească motorul pe care îl construiesc, atunci vor putea să utilizeze proprietăți în loc de metode.

Utilizarea metodei de clasă dublă scapă de orice restricții privind imposibilitatea de a utiliza declarația new pentru a ascunde membrii. Pur și simplu nu puteți folosi override dacă membrii sunt marcați ca fiind virtuali.

public class APIClass
{
    private static const string DllName = "external.dll";

    [DllImport(DllName)]
    public extern unsafe uint external_setSomething(int x, uint y);

    [DllImport(DllName)]
    public extern unsafe uint external_getSomething(int x, uint* y);

    public enum valueEnum
    {
        On = 0x01000000;
        Off = 0x00000000;
        OnWithOptions = 0x01010000;
        OffWithOptions = 0x00010000;
    }
}

public class APIUsageClass : APIClass
{
    public int Identifier;
    private APIClass m_internalInstance = new APIClass();

    public valueEnum Something
    {
        get
        {
            unsafe
            {
                valueEnum y;
                fixed (valueEnum* yPtr = &y)
                {
                    m_internalInstance.external_getSomething(Identifier, yPtr);
                }
                return y;
            }
        }
        set
        {
            m_internalInstance.external_setSomething(Identifier, value);
        }
    }

    new private uint external_setSomething(int x, float y) { return 0; }
    new private unsafe uint external_getSomething(int x, float* y) { return 0; }
}

Acum valueEnum este disponibil pentru ambele clase, dar numai proprietatea este vizibilă în clasa APIUsageClass. Clasa APIClass este încă disponibilă pentru persoanele care doresc să extindă API-ul original sau să o folosească într-un mod diferit, iar APIUsageClass este disponibil pentru cei care doresc ceva mai simplu.

În cele din urmă, ceea ce voi face este să fac APIClass intern și să-mi expun clasa moștenită.

0
adăugat
Cum se utilizează aceasta pentru proprietățile de dependență?
adăugat autor James M

Am testat toate soluțiile propuse și nu ascund cu adevărat noi membri.

Dar acesta nu:

[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public new string MyHiddenProperty
{ 
    get { return _myHiddenProperty; }
}

Dar, în code-behide, este încă accesibil, deci adăugați și atributul obișnuit

[Obsolete("This property is not supported in this class", true)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public new string MyHiddenProperty
{ 
    get { return _myHiddenProperty; }
}
0
adăugat

Pentru a ascunde complet și a marca să nu folosiți, inclusiv intellisense, ceea ce cred că este ceea ce majoritatea cititorilor se așteaptă ...

[Obsolete("Not applicable in this class.")] 
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
0
adăugat

Puteți utiliza o interfață

    public static void Main()
    {
        NoRemoveList testList = ListFactory.NewList();

        testList.Add(" this is ok ");

        // not ok
        //testList.RemoveAt(0);
    }

    public interface NoRemoveList
    {
        T this[int index] { get; }
        int Count { get; }
        void Add(T item);
    }

    public class ListFactory
    {
        private class HiddenList: List, NoRemoveList
        {
            // no access outside
        }

        public static NoRemoveList NewList()
        {
            return new HiddenList();
        }
    }
0
adăugat