2008-08-04 9 views
33

Estoy buscando alguna forma de ocultar eficazmente miembros heredados. Tengo una biblioteca de clases que heredan de clases base comunes. Algunas de las clases descendientes más recientes heredan propiedades de dependencia que se han vuelto vestigiales y pueden ser un poco confusas al usar IntelliSense o al usar las clases en un diseñador visual.Esconder miembros heredados

Estas clases son todos los controles escritos para ser compilados para WPF o Silverlight 2.0. Sé de ICustomTypeDescriptor y ICustomPropertyProvider, pero estoy bastante seguro de que no se pueden usar en Silverlight.

No es tanto un problema funcional como un problema de usabilidad. ¿Que debería hacer?

actualización

Algunas de las propiedades que realmente me gusta esconder provienen de antepasados ​​que no son mi propio y debido a una herramienta específica los estoy diseñando, no puedo hacer miembro de ocultar con el operador new. (Sé, es ridículo)

Respuesta

32

redefina como Michael Sugiere above y para evitar que la gente de usar el anulado métodos , márcalos como obsoletos:

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

Si el segundo parm se establece en verdadero, se generará un error de compilación si alguien intenta llamar a ese método y la cadena en el primer parm es el mensaje.Si parm2 es falso, solo se generará una advertencia del compilador.

+0

¿No puede sellarlo, también, con el mismo efecto? –

+0

@JamesM no obselete con verdadero impide miembro _acceso_, sellado previene miembro _herida_. Por lo tanto, no se puede derivar una clase sellada, y un método sellado permite anular a otros miembros de la clase, pero impide que ese miembro sea anulado. Sealed no impide llamar a esa clase o miembro, mientras que obselete con verdadero arroja un error de compilación si intentas llamarlo. –

+0

@RobertPetz cuando se usa obsoleto, da una advertencia, no un error. Gran diferencia. –

16

Aunque no se puede evitar el uso de los miembros heredados a mi conocimiento, usted debe ser capaz de ocultarlos de IntelliSense mediante el EditorBrowsableAttribute: Editar

Using System.ComponentModel; 

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

: acabamos de ver esto en los comentarios de la documentación, que lo hace un poco inútil para este propósito:

Hay una nota destacada que establece que este atributo "no suprime miembros de una clase en el mismo conjunto". Eso es cierto, pero no completo. En realidad, el atributo no suprime miembros de una clase en la misma solución.

8

Creo que es la mejor manera menos hackish es considerar la composición en lugar de la herencia.

O bien, puede crear una interfaz que tenga los miembros que desee, hacer que su clase derivada implemente esa interfaz y programar contra la interfaz.

13

Una cosa potencial que puede hacer es contener el objeto en lugar de extenderlo desde la otra clase. Esto le dará la mayor flexibilidad en términos de exponer lo que quiere exponer, pero si absolutamente necesita que el objeto sea de ese tipo, no es la solución ideal (sin embargo, podría exponer el objeto de un getter).

Por lo tanto:

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

se convierte en:

public class MyClass 
{ 
    private BaseClass baseClass; 

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

O: (? Sp)

public class MyClass 
{ 
    private BaseClass baseClass; 

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

Sé que ha habido varias respuestas a esto, y es bastante viejo ahora, pero el método más simple para hacer esto es simplemente declararlos como new private.

Considere un ejemplo en el que estoy trabajando actualmente, donde tengo una API que pone a disposición todos los métodos en una DLL de terceros. Tengo que tomar sus métodos, pero quiero usar una propiedad .Net, en lugar de un método "getThisValue" y "setThisValue". Entonces, construyo una segunda clase, heredo la primera, hago una propiedad que usa los métodos get y set, y luego anulo los métodos get y set originales como privados. Todavía están disponibles para cualquiera que quiera construir algo diferente en ellos, pero si solo quieren usar el motor que estoy construyendo, entonces podrán usar propiedades en lugar de métodos.

Al utilizar el método de clase doble se elimina cualquier restricción al no poder usar la declaración new para ocultar los miembros. Simplemente no puede usar override si los miembros están marcados como virtuales.

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

Ahora valueEnum está disponible para ambas clases, pero solo la propiedad está visible en la clase APIUsageClass. La clase APIClass todavía está disponible para las personas que desean extender la API original o usarla de una manera diferente, y APIUsageClass está disponible para aquellos que quieren algo más simple.

En última instancia, lo que haré es hacer que el APIClass sea interno y solo exponer mi clase heredada.

+0

¿Cómo se usa esto para las propiedades de dependencia? –

1

Probé todas las soluciones propuestas y realmente no ocultan nuevos miembros.

Pero esto se hace:

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

Pero en código behide sigue siendo accesible, por lo que añadir Atributo así obsoleto

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

Para ocultar totalmente y Mark no utilizar, incluyendo IntelliSense cuales Creo que es lo que la mayoría de los lectores esperan ...

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

Puede usar una interfaz

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(); 
     } 
    } 
Cuestiones relacionadas