Domanda

Sto cercando un modo per nascondere efficacemente i membri ereditati.Ho una libreria di classi che ereditano dalle classi base comuni.Alcune delle classi discendenti più recenti ereditano proprietà di dipendenza che sono diventate vestigiali e possono creare un po' di confusione quando si utilizza IntelliSense o utilizzando le classi in un visual designer.

Queste classi sono tutti controlli scritti per essere compilati per WPF o Silverlight 2.0.Lo so ICustomTypeDescriptor E ICustomPropertyProvider, ma sono abbastanza certo che non possano essere utilizzati in Silverlight.

Non è tanto un problema funzionale quanto un problema di usabilità.Cosa dovrei fare?

Aggiornamento

Alcune delle proprietà che vorrei davvero nascondere provengono da antenati che non sono i miei e, a causa di uno strumento specifico per cui sto progettando, non posso nascondere i membri con new operatore.(Lo so, è ridicolo)

È stato utile?

Soluzione

Sostituiscili come suggerisce Michael Sopra e per impedire alle persone di utilizzare i metodi sovrascritti (sp?), contrassegnali come obsoleti:

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

Se il secondo parametro è impostato su true, verrà generato un errore del compilatore se qualcuno tenta di chiamare quel metodo e la stringa nel primo parametro è il messaggio.Se parm2 è false verrà generato solo un avviso del compilatore.

Altri suggerimenti

Sebbene non sia possibile impedire l'utilizzo di tali membri ereditati, a quanto ne so, dovresti essere in grado di nasconderli da IntelliSense utilizzando il file EditorBrowsableAttribute:

Using System.ComponentModel;

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

Modificare: Ho appena visto questo nei commenti della documentazione, il che lo rende abbastanza inutile per questo scopo:

C'è una nota importante che afferma che questo attributo "non sopprime i membri di una classe nello stesso assembly".Questo è vero ma non completo.In realtà, l'attributo non elimina i membri di una classe nella stessa soluzione.

Una potenziale cosa che puoi fare è contenere l'oggetto anziché estenderlo dall'altra classe.Questo ti darà la massima flessibilità in termini di esposizione di ciò che vuoi esporre, ma se hai assolutamente bisogno che l'oggetto sia di quel tipo non è la soluzione ideale (tuttavia potresti esporre l'oggetto da un getter).

Così:

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

Diventa:

public class MyClass
{
    private BaseClass baseClass;

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

O:

public class MyClass
{
    private BaseClass baseClass;

    public BaseClass BaseClass
    {
        get
        {
            return baseClass;
        }
    }
}

Penso che il modo migliore meno hacker sia considerare la composizione anziché l'ereditarietà.

Oppure potresti creare un'interfaccia con i membri desiderati, fare in modo che la tua classe derivata implementi quell'interfaccia e programmi contro l'interfaccia.

So che ci sono state diverse risposte a questa domanda, ed è piuttosto vecchia ormai, ma il metodo più semplice per farlo è semplicemente dichiararle come new private.

Considera un esempio su cui sto attualmente lavorando, in cui ho un'API che rende disponibile ogni metodo in una DLL di terze parti.Devo prendere i loro metodi, ma voglio usare una proprietà .Net, invece di un metodo "getThisValue" e "setThisValue".Quindi, creo una seconda classe, eredito la prima, creo una proprietà che utilizza i metodi get e set, quindi sovrascrivo i metodi get e set originali come privati.Sono ancora disponibili per chiunque desideri creare qualcosa di diverso su di essi, ma se vogliono semplicemente utilizzare il motore che sto creando, saranno in grado di utilizzare le proprietà anziché i metodi.

L'uso del metodo della doppia classe elimina qualsiasi restrizione sull'impossibilità di utilizzare il file new dichiarazione per nascondere i membri.Semplicemente non puoi usarlo override se i membri sono contrassegnati come 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; }
}

Ora valueEnum è disponibile per entrambe le classi, ma solo la proprietà è visibile nella classe APIUsageClass.La classe APIClass è ancora disponibile per le persone che desiderano estendere l'API originale o utilizzarla in un modo diverso, mentre APIUsageClass è disponibile per coloro che desiderano qualcosa di più semplice.

Alla fine, quello che farò è rendere APIClass interna ed esporre solo la mia classe ereditata.

Nascondere completamente e contrassegnare per non utilizzare, incluso IntelliSense che credo sia ciò che la maggior parte dei lettori si aspetta...

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

Ho testato tutte le soluzioni proposte e non nascondono realmente i nuovi membri.

Ma questo FA:

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

Ma in code-behide è ancora accessibile, quindi aggiungi anche l'attributo obsoleto

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

È possibile utilizzare un'interfaccia

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

        testList.Add(" this is ok ");

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

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

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

        public static NoRemoveList<T> NewList()
        {
            return new HiddenList();
        }
    }
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top