Masquage des membres hérités

Je cherche un moyen de cacher efficacement les membres hérités. J'ai une bibliothèque de classes qui hérite des classes de base communes. Certaines des classes descendantes les plus récentes héritent des propriétés de dépendance qui sont devenues vestigiales et peuvent être un peu déroutantes lorsque vous utilisez IntelliSense ou que vous utilisez les classes dans un concepteur visuel.

Ces classes sont toutes les commandes écrites pour être compilées pour wpf ou Silverlight 2.0. Je connais ICustomTypeDescriptor et ICustomPropertyProvider , mais je suis assez certain que ceux-ci ne peuvent pas être utilisés dans Silverlight.

Ce n'est pas tant un problème fonctionnel qu'un problème d'utilisabilité. Que devrais-je faire?

Mise à jour

Certaines des propriétés que j'aimerais vraiment cacher proviennent d'ancêtres qui ne sont pas les miens et à cause d'un outil spécifique pour lequel je conçois, je ne peux pas masquer les membres avec l'opérateur new . (Je sais, c'est ridicule)

0

8 Réponses

Bien que vous ne puissiez pas empêcher l'utilisation de ces membres hérités à ma connaissance, vous devriez pouvoir les cacher d'IntelliSense en utilisant le 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:

Une note importante indique que cet attribut "ne supprime pas les membres d'une classe dans le même assemblage". C'est vrai mais pas complet. En fait, l'attribut ne supprime pas les membres d'une classe dans la même solution.

0
ajouté

Une chose potentielle que vous pouvez faire est de contenir l'objet plutôt que de s'étendre de l'autre classe. Cela vous donnera la plus grande flexibilité en termes d'exposition de ce que vous voulez exposer, mais si vous avez absolument besoin que l'objet soit de ce type, ce n'est pas la solution idéale (cependant vous pouvez exposer l'objet à partir d'un getter).

Ainsi:

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

Devient:

public class MyClass
{
    private BaseClass baseClass;

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

Ou:

public class MyClass
{
    private BaseClass baseClass;

    public BaseClass BaseClass
    {
        get
        {
            return baseClass;
        }
    }
}
0
ajouté

Je pense que vous êtes le meilleur moyen moins hackish est de considérer la composition par opposition à l'héritage.

Ou, vous pouvez créer une interface qui a les membres que vous voulez, que votre classe dérivée implémente cette interface, et programme contre l'interface.

0
ajouté

Remplacez-les comme Michael Suggests ci-dessus et pour empêcher les gens d'utiliser les méthodes surchargées (sp?), Marquez-les comme obsolètes:

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

Si le second parm est défini sur true, une erreur de compilation sera générée si quelqu'un essaie d'appeler cette méthode et que la chaîne du premier parm est le message. Si parm2 est faux, seul un avertissement du compilateur sera généré.

0
ajouté
Ne peux-tu pas le sceller aussi avec le même effet?
ajouté l'auteur James M, source
@RobertPetz lors de l'utilisation obsolète, il donne un avertissement, pas une erreur. Grande différence.
ajouté l'auteur James M, source
@RobertPetz Vous n'avez clairement pas lu le mien, cependant, bravo pour le sarcasme inutile.
ajouté l'auteur James M, source
@JamesM no obselete with true empêche le membre access , sealed empêche le membre inheritance . Donc, une classe scellée ne peut pas être dérivée, et une méthode scellée permet à d'autres membres de la classe d'être surchargés mais empêche ce membre d'être écrasé. Scellé n'empêche pas d'appeler cette classe ou membre, alors que obselete avec true renvoie une erreur de compilation si vous essayez de l'appeler.
ajouté l'auteur Robert Petz, source
@JamesM uhm ... avez-vous lu la réponse que vous avez littéralement commentée en premier?
ajouté l'auteur Robert Petz, source
@JamesM lol je l'ai fait, c'est pourquoi j'ai répondu à votre question initiale en notant pourquoi la chasse d'eau n'a pas effectué la même tâche. Ensuite, vous avez noté que Obselete ne donne qu'un avertissement, ce qui est incorrect car le second argument de true provoque une erreur du compilateur plutôt qu'un avertissement - comme la réponse que vous avez directement commentée États. Si je vous comprends mal, j'apprécie les précisions. Voici la Source MSDN
ajouté l'auteur Robert Petz, source

Je sais qu'il y a eu plusieurs réponses à cela, et c'est assez ancien maintenant, mais la méthode la plus simple pour le faire est simplement de les déclarer comme new private .

Considérons un exemple sur lequel je travaille actuellement, où j'ai une API qui rend disponibles toutes les méthodes dans une DLL tierce. Je dois prendre leurs méthodes, mais je veux utiliser une propriété .Net, au lieu d'une méthode "getThisValue" et "setThisValue". Donc, je construis une deuxième classe, hérite la première, crée une propriété qui utilise les méthodes get et set, puis substitue les méthodes get et set d'origine comme private. Ils sont toujours disponibles pour quiconque veut construire quelque chose de différent sur eux, mais s'ils veulent juste utiliser le moteur que je construis, ils pourront utiliser des propriétés au lieu de méthodes.

L'utilisation de la méthode de la double classe élimine toute restriction empêchant l'utilisation de la déclaration new pour masquer les membres. Vous ne pouvez simplement pas utiliser override si les membres sont marqués comme virtuels.

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; }
}

Maintenant valueEnum est disponible pour les deux classes, mais seule la propriété est visible dans la classe APIUsageClass. La classe APIClass est toujours disponible pour les personnes qui souhaitent étendre l'API d'origine ou l'utiliser différemment, et APIUsageClass est disponible pour ceux qui veulent quelque chose de plus simple.

En fin de compte, ce que je vais faire est de rendre l'APIClass interne, et exposer seulement ma classe héritée.

0
ajouté
Comment l'utilise-t-on pour les propriétés de dépendance?
ajouté l'auteur James M, source

J'ai testé toutes les solutions proposées et elles ne cachent pas vraiment de nouveaux membres.

Mais celui-ci:

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

Mais dans code-behide c'est toujours accessible, donc ajoutez aussi Attribut Obsolète

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

Pour masquer complètement et marquer de ne pas utiliser, y compris intellisense qui je crois est ce que la plupart des lecteurs attendent ...

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

Vous pouvez utiliser une interface

    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
ajouté