c# - protección - error 2 se requiere una referencia de objeto para el campo método o propiedad no estáticos
¿Por qué C#no admite la intersección de accesibilidad protegida e interna? (7)
Entonces, ¿por qué C # no debería soportarlo?
Pregunta equivocada. La pregunta debería ser "¿por qué debería C # ser protected and internal
?"
Tenga en cuenta que el estado natural de una característica es que no se implemente. Implementar una función es muy costoso en términos de recursos, pruebas y, no olvidemos, el costo de oportunidad (lo que significa que desplaza a otras funciones). Entonces, para superar este gasto, es mejor que haya un beneficio extremadamente claro para implementar una función que supere estos costos.
En particular, ¿cuál es el valor de protected and internal
? Realmente no hay una buena razón para restringir la accesibilidad solo a las clases derivadas en el mismo ensamblaje.
En mi opinión, es extraño que el CLR lo soporte, pero lo hace. Eso no significa que C # necesite hacerlo.
protegido interno:
La unión de accesibilidad protegida e interna (esto es menos restrictivo que protegido o interno solo)
El CLR tiene el concepto de intersección de accesibilidad protegida e interna , pero C # no lo admite.
Así que mi pregunta es:
¿Cuál es el significado de omitir este modificador de acceso , hay una razón concreta? Entonces, ¿por qué C # no debería soportarlo?
Actualización: C # 7.2 está introduciendo esto con el modificador de acceso private protected
, lo que parece incorrecto de varias maneras pero evita gran parte de la posibilidad de confusión que describo a continuación, por lo que quizás sea el mejor de un grupo malo.
Personalmente, he querido esto unas cuantas veces. Hay ocasiones en que uno expone una clase y una o más clases derivadas de ella como public
en un ensamblaje, y hay ocasiones en que un miembro de la clase base solo es usado por esas clases derivadas y no debe ser expuesto a clases protegidas en otras asambleas (a menudo el constructor, para evitar que otras asambleas tengan clases que se derivan de ellas).
Por supuesto, siempre es bueno definir su acceso de la forma más restrictiva posible, por lo que la intersección de protegido e interno es precisamente lo que se busca aquí.
En su lugar, he tenido que guardarlo al declarar internal
al miembro. Ahora hay un potencial de errores en mi código que no habría estado allí si usara un lenguaje que me permitiera usar esa intersección.
Sin embargo, considere la desventaja.
Tal como está, hay cierta confusión sobre la forma en que la protected internal
proporciona la unión de protected
e internal
. Probablemente sea el acceso más incomprendido, juzgado por preguntas en sitios como este.
¿Cómo deberíamos llamarlo? internal protected
? ¿Te imaginas con qué frecuencia las personas se confunden con protected internal
? Queremos algo más claramente diferenciado, y queremos lo mismo para internal protected
(porque aún aumentamos su potencial de confusión). No es un problema imposible de responder, pero mantener una cantidad baja de palabras clave también es una buena idea.
Incluso si se encuentra una respuesta perfecta a la pregunta de denominación, el potencial de confusión al introducir otro nivel de acceso no se elimina por completo.
Así que con eso en mente, echemos un vistazo al alza de nuevo. Ya no tenemos que controlar las veces que lo necesitamos mediante el uso internal
, reduciendo los errores causados por el uso inadecuado de dicho miembro. De acuerdo, ¿con qué frecuencia aparece eso y qué tan probable es que esos errores sean realmente? No muy a menudo realmente, y no muy probable.
Por lo tanto, si bien me encuentro ocasionalmente deseando que C # tuviera esto, un momento de pausa normalmente me alegra de que no lo hicieran.
Fue una decisión de diseño, pero considera lo que significa:
- Accesible solo a clases derivadas en el mismo ensamblaje.
Este no es un límite muy útil, no puedo pensar en un caso de uso claro.
Y es por eso que probablemente no valió la pena proponer una nueva palabra clave (combinación).
Preferiría preguntar por qué el CLR lo apoya. La ortogonalidad supongo.
La intersección de protected
e internal
bajaría a una simple internal
para código externo a su biblioteca, lo que significa que no sería accesible, ya sea de clases derivadas o de otro tipo.
Como tal, el único beneficio que una protected internal intersection
serviría es disciplinarse a sí mismo, como desarrollador de su biblioteca, no para acceder al tipo / miembro excepto desde las mismas clases o clases derivadas dentro de su biblioteca. No hará ninguna diferencia para los consumidores de su biblioteca, ya que su semántica sería idéntica a una simple internal
.
Dicho esto, no me hubiera parecido irrazonable que se permitiera en C #. La autodisciplina a menudo resulta útil; Es la razón por la que los diseñadores de idiomas diferenciaron entre private
e internal
, a pesar de que los dos son idénticos para los consumidores externos.
Sin embargo, dado que la distinción entre la intersección y la llanura internal
es pequeña, probablemente optaron por excluirla para mitigar el riesgo de que los desarrolladores la confundan con la unión protected internal
más útil.
Por lo que sé, puede usar la intersección de modificadores de acceso internos y protegidos pero no con la interpretación que desea (tal vez por lo que dijo Henk):
Protegido: solo se puede acceder al tipo o miembro por código en la misma clase o estructura, o en una clase derivada.
Interno: Se puede acceder al tipo o miembro mediante cualquier código en el mismo ensamblaje, pero no desde otro ensamblaje.
Interno protegido: Se puede acceder al tipo o miembro mediante cualquier código en el mismo ensamblaje, o mediante cualquier clase derivada en otro ensamblaje.
Quería hacer esta misma pregunta, pero afortunadamente, también encontré esta para mí.
Puedo entender el punto de vista de que requeriría al menos una nueva palabra clave o una nueva semántica para las palabras clave existentes, por lo que no se admitió porque el costo-beneficio no funcionó a su favor.
Sin embargo, me pregunto si es legítimo evitar la implementación de esta característica de CLR debido al caso de uso limitado o porque podría confundir a la gente.
Un argumento dado anteriormente es que su único uso sería hacer cumplir la autodisciplina.
Pero entonces podría decirse lo mismo de cualquier modificador de visibilidad que no sea public
. La idea, también, de que solo se aplicaría a ''un solo desarrollador de una sola biblioteca'' también es claramente errónea. Muchas bibliotecas son desarrolladas por equipos de personas, y es completamente natural que un desarrollador dentro de ese equipo agregue un miembro que él o ella querría restringir solo a los tipos internos derivados de su base.
Luego está este escenario:
internal class Foo {
}
public class PublicBase {
protected Foo MyFoo { get; set; }
}
En el caso aquí, tengo un tipo interno que quiero exponer en una clase, pero solo quiero exponerlo a tipos derivados. Dado que el tipo es interno, eso significa implícitamente los tipos derivados en el mismo ensamblaje. Los tipos externos todavía pueden heredar legítimamente de este tipo, pero no necesitarán usar este miembro.
En esta situación, estoy atascado: no puedo usar protected
, ni puedo usar protected internal
.
En su lugar, tengo que usar internal
, que transmite incorrectamente a otros miembros de mi equipo que debe usarse desde un código fuera de la clase. Claro que puedo pegarle un comentario (e incluso pegar el EditorBrowsableAttribute
of Never
en él, pero eso también lo escondería de los herederos internos), pero no es lo mismo.
Tal como está, la única forma en que puedo lograr esto es hackear el ensamblaje con una reescritura de IL después de la compilación, pero necesito esta visibilidad (o falta de ella) en tiempo de compilación, no después de que se construya.
En última instancia, los argumentos sobre "qué palabras clave utilizaría" o " cómo se implementaría " son irrelevantes para mí: soy el programador, no el diseñador de lenguaje C #.
Igualmente, tengo que decir que argumentos como "Bueno, protected internal
es lo suficientemente confuso para muchos" también son irrelevantes. Hay tantos desarrolladores con los que me he puesto en contacto, ya sea en persona o virtualmente, que no entienden cosas como ?:
O restricciones genéricas: adivina qué, ¡no las usan! Eso no significa que no deba.
Así que sí, entiendo las razones para no implementarlo, pero no estoy de acuerdo con ellos, por lo tanto, mi respuesta de por qué C # no lo admite es porque los diseñadores de C # lo entendieron mal.
Y sí, estoy listo para el calor que podría traer a mi puerta :)
Siempre puedes hacer:
public MyExternallySealedClass
{
internal MyExternallySealedClass() {...}
...
}
Siempre y cuando no permita que un consumidor externo ejemplifique el objeto, ¿qué le importaría si intentara derivarlo? Respuesta corta, la función que solicita no trae nada nuevo y ya tiene herramientas para hacer lo que solicita.