Hay mucho código en uno de nuestros proyectos que se ve así:
internal static class Extensions
{
public static string AddFoo(this string s)
{
if (s == null)
{
return "Foo";
}
return $({s}Foo);
}
}
¿Hay alguna razón explícita para hacer esto que no sea "es más fácil hacer público el tipo más tarde?"
Sospecho que solo importa en casos extremos muy extraños (reflejo en Silverlight) o en absoluto.
return s + "Foo";
? Al+
operador no le importan las cadenas nulas o vacías.Respuestas:
ACTUALIZACIÓN: Esta pregunta fue el tema de mi blog en septiembre de 2014 . Gracias por la gran pregunta!
Existe un debate considerable sobre esta cuestión, incluso dentro del propio equipo compilador.
En primer lugar, es sabio entender las reglas. Un miembro público de una clase o estructura es un miembro accesible para cualquier cosa que pueda acceder al tipo que lo contiene . Entonces, un miembro público de una clase interna es efectivamente interno.
Entonces, dada una clase interna, ¿deberían sus miembros a los que desea acceder en la asamblea ser marcados como públicos o internos?
Mi opinión es: marcar tales miembros como público.
Utilizo "public" para significar "este miembro no es un detalle de implementación". Un miembro protegido es un detalle de implementación; hay algo al respecto que será necesario para que una clase derivada funcione. Un miembro interno es un detalle de implementación; Algo más interno de esta asamblea necesita el miembro para funcionar correctamente. Un miembro público dice "este miembro representa la funcionalidad clave y documentada proporcionada por este objeto".
Básicamente, mi actitud es: supongamos que decidí convertir esta clase interna en una clase pública. Para hacer eso, quiero cambiar exactamente una cosa : la accesibilidad de la clase. Si convertir una clase interna en una clase pública significa que también tengo que convertir a un miembro interno en un miembro público, entonces ese miembro era parte de la superficie pública de la clase, y debería haber sido público en primer lugar.
Otras personas no están de acuerdo. Hay un contingente que dice que quieren poder echar un vistazo a la declaración de un miembro y saber de inmediato si solo se llamará desde el código interno.
Desafortunadamente, eso no siempre funciona bien; por ejemplo, una clase interna que implementa una interfaz interna todavía tiene que tener los miembros implementadores marcados como públicos, porque son parte de la superficie pública de la clase .
fuente
public
es muy convincente. Sin embargo, creo que "no siempre funciona bien ..." es especialmente poderoso. La pérdida de consistencia devalúa cualquier beneficio "de un vistazo". Usarinternal
de esta manera significa construir deliberadamente intuiciones que a veces están mal. Tener una intuición mayormente correcta es IMO, algo horrible para programar.Si la clase es
internal
, no importa desde el punto de vista de la accesibilidad si marca un métodointernal
o nopublic
. Sin embargo, sigue siendo bueno usar el tipo que usarías si la clase lo fuerapublic
.Si bien algunos han dicho que esto facilita las transiciones de
internal
apublic
. También sirve como parte de la descripción del método.Internal
los métodos generalmente se consideran inseguros para el acceso sin restricciones, mientras que lospublic
métodos se consideran (en su mayoría) juegos gratuitos.Al usar
internal
opublic
como lo haría en unapublic
clase, se asegura de comunicar qué estilo de acceso se espera, al tiempo que facilita el trabajo requerido para hacer la clasepublic
en el futuro.fuente
A menudo marco mis métodos en clases internas como públicas en lugar de internos como a) realmente no importa yb) Uso interno para indicar que el método es interno a propósito (hay alguna razón por la que no quiero exponer esto método en una clase pública. Por lo tanto, si tengo un método interno realmente tengo que entender la razón por la cual es interno antes de cambiarlo a público, mientras que si estoy tratando con un método público en una clase interna realmente tengo que pensar por qué La clase es interna en lugar de por qué cada método es interno.
fuente
Sospecho que "¿es más fácil hacer público el tipo más tarde?" Lo es.
Las reglas de alcance significan que el método solo será visible como
internal
, por lo que realmente no importa si los métodos están marcadospublic
o no.internal
.Una posibilidad que viene a la mente es que la clase era pública y luego se cambió a
internal
y el desarrollador no se molestó en cambiar todos los modificadores de accesibilidad del método.fuente
En algunos casos, también puede ser que el tipo interno implemente una interfaz pública, lo que significaría que cualquier método definido en esa interfaz aún debería declararse como público.
fuente
Es lo mismo, el método público se marcará realmente como interno ya que está dentro de una clase interna, pero tiene una ventaja (como adivinó), si desea marcar la clase como pública, debe cambiar menos código.
fuente
internal
dice que solo se puede acceder al miembro desde el mismo ensamblado. Otras clases en esa asamblea pueden acceder alinternal public
miembro, pero no sería capaz de acceder a unaprivate
oprotected
miembro,internal
o no.fuente
internal
lugar depublic
, su visibilidad no cambiaría. Creo que eso es lo que pregunta el OP.En realidad luché con esto hoy. Hasta ahora, habría dicho que todos los métodos deberían estar marcados
internal
si la clase fuerainternal
y hubiera considerado cualquier otra cosa simplemente una mala codificación o pereza, especialmente en el desarrollo empresarial; Sin embargo, tuve que subclasificar unapublic
clase y anular uno de sus métodos:El método DEBE ser
public
y me hizo pensar que realmente no hay ningún punto lógico para establecer métodos comointernal
menos que realmente lo sean, como dijo Eric Lippert.Hasta ahora nunca me he detenido a pensar en ello, simplemente lo acepté, pero después de leer la publicación de Eric realmente me hizo pensar y después de mucho pensarlo tiene mucho sentido.
fuente
Hay una diferencia En nuestro proyecto, hemos realizado muchas clases internas, pero hacemos pruebas unitarias en otro ensamblaje y en nuestra información de ensamblaje utilizamos InternalsVisibleTo para permitir que el ensamblaje UnitTest llame a las clases internas. He notado que si la clase interna tiene un constructor interno, no podemos crear una instancia usando Activator.CreateInstance en el ensamblaje de prueba de la unidad por alguna razón. Pero si cambiamos el constructor a public pero la clase sigue siendo interna, funciona bien. Pero supongo que este es un caso muy raro (como dijo Eric en la publicación original: Reflexión).
fuente
Creo que tengo una opinión adicional sobre esto. Al principio, me preguntaba cómo tiene sentido declarar algo al público en una clase interna. Luego terminé aquí, leyendo que podría ser bueno si luego decides cambiar la clase a público. Cierto. Entonces, un patrón se formó en mi mente: si no cambia el comportamiento actual, entonces sea permisivo y permita cosas que no tienen sentido (y no duelen) en el estado actual del código, pero luego lo haría, si usted Cambiar la declaración de la clase.
Me gusta esto:
De acuerdo con el "patrón" que he mencionado anteriormente, esto debería estar perfectamente bien. Sigue la misma idea. Se comporta como un
private
método, ya que no puede heredar la clase. Pero si elimina lasealed
restricción, sigue siendo válida: las clases heredadas pueden ver este método, que es absolutamente lo que quería lograr. Pero recibes una advertencia:CS0628
oCA1047
. Ambos se trata de no declararprotected
miembros en unasealed
clase. Además, he encontrado un acuerdo total, sobre eso no tiene sentido: advertencia de 'Miembro protegido en clase sellada' (una clase singleton)Entonces, después de esta advertencia y la discusión vinculada, he decidido hacer que todo sea interno o menos, en una clase interna, porque se ajusta más a ese tipo de pensamiento, y no mezclamos diferentes "patrones".
fuente