Pregunta

¿Podría explicar cuál es el uso práctico de la palabra clave internal en C #?

Sé que el modificador interno limita el acceso al ensamblaje actual, pero ¿cuándo y en qué circunstancias debo usarlo?

¿Fue útil?

Solución

Clases / métodos de utilidad o de ayuda a los que le gustaría acceder desde muchas otras clases dentro del mismo ensamblaje, pero que quiere asegurar que el código de otros ensamblajes no pueda acceder.

De MSDN (a través de archive.org):

  

Un uso común del acceso interno es en el desarrollo basado en componentes porque permite que un grupo de componentes coopere de manera privada sin estar expuesto al resto del código de la aplicación. Por ejemplo, un marco para la creación de interfaces gráficas de usuario podría proporcionar clases de control y formulario que cooperen utilizando miembros con acceso interno. Dado que estos miembros son internos, no están expuestos al código que utiliza el marco.

También puede usar el modificador interno junto con los InternalsVisibleTo atributo de nivel de ensamblaje para crear " amigo " Conjuntos que tienen acceso especial a las clases internas de ensamblados de destino.

Esto puede ser útil para la creación de conjuntos de prueba de unidad que luego pueden llamar a los miembros internos del conjunto a probar. Por supuesto, a ningún otro conjunto se le otorga este nivel de acceso, por lo que cuando libera su sistema, se mantiene la encapsulación.

Otros consejos

Si Bob necesita BigImportantClass, entonces Bob necesita que las personas que poseen el proyecto A se registren para garantizar que BigImportantClass se escribirá para satisfacer sus necesidades, se probará para asegurar que cumpla con sus necesidades, se documente que cumpla con sus necesidades y que se pondrá en marcha un proceso para garantizar que nunca se modifique para que ya no satisfaga sus necesidades.

Si una clase es interna, entonces no tiene que pasar por ese proceso, lo que ahorra presupuesto para el Proyecto A que pueden gastar en otras cosas.

El punto interno no es que le dificulte la vida a Bob. Es que le permite controlar qué promesas caras está haciendo el Proyecto A sobre las características, el tiempo de vida, la compatibilidad, etc.

Otra razón para usar interno es si ofuscas tus binarios. El ofuscador sabe que es seguro mezclar el nombre de la clase de cualquier clase interna, mientras que el nombre de las clases públicas no puede ser codificado, ya que podría romper las referencias existentes.

Si está escribiendo una DLL que encapsula una tonelada de funcionalidades complejas en una API pública simple, entonces & # 8220; internal & # 8221; se utiliza en los miembros de la clase que no deben ser expuestos públicamente.

La complejidad de ocultación (a.k.a. encapsulación) es el concepto principal de ingeniería de software de calidad.

La palabra clave interna se usa mucho cuando creas un contenedor sobre un código no administrado.

Cuando tiene una biblioteca basada en C / C ++ que desea DllImport, puede importar estas funciones como funciones estáticas de una clase y hacerlas internas, de modo que su usuario solo tenga acceso a su envoltorio y no a la API original, por lo que No puedo meterme con nada. Como las funciones son estáticas, puede usarlas en cualquier parte del ensamblaje, para las múltiples clases de envoltorios que necesita.

Puedes echar un vistazo a Mono.Cairo, es una envoltura alrededor de la biblioteca de El Cairo que utiliza este enfoque.

Al ser impulsado por " use un modificador estricto como puedas " regla que uso interno en todos los lugares donde necesito acceder, por ejemplo, a un método de otra clase hasta que explícitamente necesito acceder a él desde otro conjunto.

Como la interfaz de ensamblaje suele ser más estrecha que la suma de las interfaces de clase, hay muchos lugares en los que la uso.

Encuentro interno que está muy usado en exceso. realmente no debería estar exponiendo cierta función solo a ciertas clases que no lo haría a otros consumidores.

Esto en mi opinión rompe la interfaz, rompe la abstracción. Esto no quiere decir que nunca se debe usar, pero una mejor solución es refactorizar a una clase diferente o ser usado de una manera diferente si es posible. Sin embargo, esto puede no ser siempre posible.

Las razones por las que puede causar problemas es que se puede acusar a otro desarrollador de crear otra clase en el mismo conjunto que el suyo. Tener elementos internos disminuye la claridad de la abstracción y puede causar problemas si se utiliza incorrectamente. Sería el mismo problema que si lo hicieras público. La otra clase que está siendo construida por el otro desarrollador sigue siendo un consumidor, al igual que cualquier clase externa. La abstracción y encapsulación de clases no es solo para la protección de clases externas, sino para todas y cada una de las clases.

Otro problema es que muchos desarrolladores pensarán que pueden necesitar usarlo en otro lugar del ensamblaje y marcarlo como interno de todos modos, aunque no lo necesiten en ese momento. Otro desarrollador puede pensar que está ahí para ser tomado. Por lo general, usted desea marcar en privado hasta que tenga una necesidad definitiva.

Pero algo de esto puede ser subjetivo, y no estoy diciendo que nunca se deba usar. Solo use cuando sea necesario.

Vio una interesante el otro día, quizás semana, en un blog que no puedo recordar. Básicamente, no puedo tomar crédito por esto, pero pensé que podría tener alguna aplicación útil.

Supongamos que desea que una clase abstracta sea vista por otro conjunto, pero no desea que alguien pueda heredarla. Sellado no funcionará porque es abstracto por una razón, otras clases en ese ensamblaje sí lo heredan. Privado no funcionará porque es posible que desee declarar una clase principal en algún lugar del otro conjunto.

namespace Base.Assembly
{
  public abstract class Parent
  {
    internal abstract void SomeMethod();
  }

  //This works just fine since it's in the same assembly.
  public class ChildWithin : Parent
  {
    internal override void SomeMethod()
    {
    }
  }
}

namespace Another.Assembly
{
  //Kaboom, because you can't override an internal method
  public class ChildOutside : Parent
  {
  }

  public class Test 
  { 

    //Just fine
    private Parent _parent;

    public Test()
    {
      //Still fine
      _parent = new ChildWithin();
    }
  }
}

Como puede ver, efectivamente permite que alguien use la clase Parent sin poder heredar de.

Este ejemplo contiene dos archivos: Assembly1.cs y Assembly2.cs. El primer archivo contiene una clase base interna, BaseClass. En el segundo archivo, un intento de crear una instancia de BaseClass producirá un error.

// Assembly1.cs
// compile with: /target:library
internal class BaseClass 
{
   public static int intM = 0;
}

// Assembly1_a.cs
// compile with: /reference:Assembly1.dll
class TestAccess 
{
   static void Main()
   {  
      BaseClass myBase = new BaseClass();   // CS0122
   }
}

En este ejemplo, usa los mismos archivos que usaste en el ejemplo 1, y cambia el nivel de accesibilidad de BaseClass a público . También cambie el nivel de accesibilidad del miembro IntM a interno . En este caso, puede crear una instancia de la clase, pero no puede acceder al miembro interno.

// Assembly2.cs
// compile with: /target:library
public class BaseClass 
{
   internal static int intM = 0;
}

// Assembly2_a.cs
// compile with: /reference:Assembly1.dll
public class TestAccess 
{
   static void Main() 
   {      
      BaseClass myBase = new BaseClass();   // Ok.
      BaseClass.intM = 444;    // CS0117
   }
}

fuente : http: //msdn.microsoft.com/en-us/library/7c5ka91b(VS.80).aspx

Un uso muy interesante de interno (el miembro interno, por supuesto, se limita solo a la asamblea en la que se declara) es obtener "amigo" Funcionalidad hasta cierto punto fuera de ella. Un miembro amigo es algo que solo es visible para ciertos otros ensamblajes fuera del ensamblaje en el que se declara. C # no tiene soporte integrado para amigos, sin embargo, el CLR sí lo tiene.

Puede usar InternalsVisibleToAttribute para declare una asamblea de amigos, y todas las referencias dentro de la asamblea de amigos tratarán a los miembros internos de su asamblea declarante como públicos dentro del alcance de la asamblea de amigos. Un problema con esto es que todos los miembros internos son visibles; no puedes escoger y elegir.

Un buen uso de InternalsVisibleTo es exponer a varios miembros internos a un ensamblaje de prueba unitaria, eliminando así la necesidad de realizar complejas reflexiones para evaluar a esos miembros. El hecho de que todos los miembros sean visibles no es un problema, sin embargo, si se toma este enfoque, las interfaces de clase son bastante pesadas y pueden arruinar la encapsulación dentro del ensamblaje declarante.

Cuando tenga métodos, clases, etc. que deban ser accesibles dentro del alcance del conjunto actual y nunca fuera de él.

Por ejemplo, un DAL puede tener un ORM, pero los objetos no deben estar expuestos a la capa empresarial; toda interacción debe realizarse mediante métodos estáticos y pasando los parámetros necesarios.

Como regla de oro hay dos tipos de miembros:

  • superficie pública : visible desde un ensamblaje externo (público, protegido y protegido interno): la persona que llama no es de confianza, por lo que se necesita la validación de parámetros, la documentación del método, etc.
  • superficie privada : no visible desde un ensamblaje externo (clases internas y privadas o privadas): la persona que llama generalmente es de confianza, por lo que se puede omitir la validación de parámetros, la documentación del método, etc.

Reducción de ruido, mientras menos tipos exponga, más sencilla será su biblioteca. La prueba de manipulación indebida / seguridad es otra (aunque Reflection puede ganar contra ella).

Las clases internas le permiten limitar la API de su ensamblaje. Esto tiene ventajas, como hacer que tu API sea más fácil de entender.

Además, si existe un error en su ensamblaje, hay menos posibilidades de que la solución introduzca un cambio importante. Sin clases internas, tendría que asumir que cambiar a los miembros públicos de cualquier clase sería un cambio importante. Con las clases internas, puede asumir que la modificación de sus miembros públicos solo rompe la API interna del ensamblaje (y cualquier ensamblado al que se hace referencia en el atributo InternalsVisibleTo).

Me gusta tener la encapsulación en el nivel de clase y en el nivel de ensamblaje. Hay algunos que no están de acuerdo con esto, pero es bueno saber que la funcionalidad está disponible.

Tengo un proyecto que usa LINQ-to-SQL para el back-end de datos. Tengo dos espacios de nombres principales: Biz y Data. El modelo de datos LINQ vive en Datos y está marcado como " interno " ;; el espacio de nombres de Biz tiene clases públicas que envuelven las clases de datos de LINQ.

Así que hay Data.Client y Biz.Client ; el último expone todas las propiedades relevantes del objeto de datos, por ejemplo:

private Data.Client _client;
public int Id { get { return _client.Id; } set { _client.Id = value; } }

Los objetos de Biz tienen un constructor privado (para forzar el uso de métodos de fábrica) y un constructor interno que se parece a esto:

internal Client(Data.Client client) {
    this._client = client;
}

Puede ser utilizado por cualquiera de las clases de negocios en la biblioteca, pero el front-end (UI) no tiene manera de acceder directamente al modelo de datos, asegurando que la capa de negocios siempre actúa como un intermediario.

Esta es la primera vez que uso mucho interno , y está resultando muy útil.

Hay casos en los que tiene sentido hacer miembros de las clases internos . Un ejemplo podría ser si desea controlar cómo se crean instancias de las clases; digamos que proporciona algún tipo de fábrica para crear instancias de la clase. Puede hacer que el interno del constructor, de modo que la fábrica (que reside en el mismo ensamblaje) pueda crear instancias de la clase, pero el código fuera de ese ensamblaje no pueda.

Sin embargo, no puedo ver ningún punto al hacer que las clases o los miembros sean internos sin razones específicas, tan poco como sea lógico que sean public , o < código> privado sin razones específicas.

lo único en lo que he usado la palabra clave interna es el código de verificación de licencia en mi producto ;-)

Un uso de la palabra clave interna es limitar el acceso a implementaciones concretas del usuario de su ensamblaje.

Si tiene una fábrica o alguna otra ubicación central para construir objetos, el usuario de su ensamblaje solo necesita lidiar con la interfaz pública o la clase base abstracta.

Además, los constructores internos le permiten controlar dónde y cuándo se crea una instancia de una clase pública.

¿Qué hay de esto?: por lo general, se recomienda que no exponga un objeto de Lista a usuarios externos de un ensamblaje, sino que exponga un IEnumerable. Pero es mucho más fácil usar un objeto de Lista dentro del ensamblaje, porque obtiene la sintaxis de la matriz y todos los demás métodos de Lista. Por lo tanto, normalmente tengo una propiedad interna que expone una lista para usarla dentro del ensamblaje.

Los comentarios son bienvenidos acerca de este enfoque.

Tenga en cuenta que cualquier clase definida como public se mostrará automáticamente en la inteligencia cuando alguien vea el espacio de nombres de su proyecto. Desde la perspectiva de la API, es importante que solo muestre a los usuarios de su proyecto las clases que pueden usar. Use la palabra clave internal para ocultar las cosas que no deberían ver.

Si su Big_Important_Class para el Proyecto A está diseñado para usarse fuera de su proyecto, no debe marcarlo como interno .

Sin embargo, en muchos proyectos, a menudo tendrá clases que solo están diseñadas para usarse dentro de un proyecto. Por ejemplo, puede tener una clase que contenga los argumentos de una invocación de hilo parametrizada. En estos casos, debe marcarlos como interno si no tiene otra razón que protegerse de un cambio de API no deseado en el futuro.

La idea es que cuando esté diseñando una biblioteca, solo las clases destinadas a uso externo (por parte de los clientes de su biblioteca) deberían ser públicas. De esta manera puedes ocultar las clases que

  1. Es probable que cambien en futuras versiones (si fuesen públicas, romperías el código del cliente)
  2. Son inútiles para el cliente y pueden causar confusión
  3. No son seguros (por lo que un uso inadecuado podría dañar tu biblioteca bastante mal)

etc.

Si está desarrollando soluciones internas que utilizando elementos internos, no es tan importante, supongo, porque generalmente los clientes tendrán contacto constante con usted y / o acceso al código. Sin embargo, son bastante críticos para los desarrolladores de bibliotecas.

Cuando tiene clases o métodos que no encajan limpiamente en el Paradigma Orientado a Objetos, que hacen cosas peligrosas, que deben llamarse desde otras clases y métodos bajo su control, y que no desea permitir cualquier otra persona lo use.

public class DangerousClass {
    public void SafeMethod() { }
    internal void UpdateGlobalStateInSomeBizarreWay() { }
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top