2009-07-21 18 views
8

Esta pregunta realmente es un poco inútil, pero tengo curiosidad:¿Por qué compila esta declaración de clase C#?

Este:

public sealed class MyClass 
{ 
    protected void MyMethod(){} 
} 

compila, pero da una advertencia

Si bien esto:

public sealed class MyClass 
{ 
    public virtual void MyMethod(){} 
} 

doesn compilar Solo por pura curiosidad, ¿hay alguna razón para esto?

+9

Yo daría una respuesta, pero por alguna razón creo que JS tendría una mejor. Hmm. –

+2

Aparentemente, JS está priorizando SO en THREAD_PRIORITY_BELOW_NORMAL - ¡rápidamente todos obtienen sus respuestas mientras usted todavía puede! – cfeduke

+0

+1 buena pregunta, nunca me he encontrado con esta causa, ni siquiera pensé en hacer esto ... ¡porque no tiene ningún sentido! –

Respuesta

4

La única razón por la que puedo pensar es que a veces tendría que escribir métodos protegidos para anular otros métodos protegidos. El lenguaje podría han sido diseñados para permitir esto:

protected override void Foo() 

pero no este

protected void Foo() 

pero que podría haber sido visto a ser un poco difícil de seguir - es la ausencia de override que lo hace inútil, mientras que en el caso de

public virtual void Foo() 

es el presencia de virtual que es inútil. La presencia de algo "incorrecto" es probablemente más fácil de entender que la ausencia de algo útil.

En este caso, ser virtual también puede tener implicaciones de rendimiento, mientras que hacer algo protegido en lugar de privado probablemente no lo haga, por lo que es un poco más severo.

Sin embargo, estas son solo conjeturas, si tenemos mucha suerte, Eric Lippert dará una respuesta más definitiva. Él es el único que quiere, no me :)

Mejor respuesta: Trato a los avisos como errores y son equivalentes de todos modos;)

+0

Ooh, buen punto, no pensé en el caso donde la clase sellada en cuestión hereda de una base y anula a un miembro protegido. Esa podría ser una razón. De hecho, le envié un correo electrónico a Eric anoche, y él respondió diciendo que lo investigará y me contestará. Mantendré abierta esta pregunta hasta que lo haga. Gracias, Jon. – BFree

+1

Hola, solo estoy adivinando, muchachos. Las notas de diseño del lenguaje documentan que la decisión de presentar un método virtual en un tipo sellado se produjo un error el 18 de octubre de 1999, pero no da ninguna justificación para la decisión. No puedo encontrar ninguna parte en las notas que justifique por qué la introducción de un nuevo miembro protegido debe ser legal. mejor suposición: esto probablemente fue simplemente un descuido en la primera versión, y luego se convirtió en un cambio decisivo para arreglarlo alguna vez. –

+2

@Eric: Fuera de interés, ¿dónde está esto en la especificación? No parece estar en el parte introductoria de 10.6 wh ich enumera las reglas para combinaciones válidas de modificadores. Pensé que encontraría la regla y luego vería si se menciona en cualquiera de las especificaciones anotadas ... y ahora no puedo encontrar la regla. No puedo verlo en 10.6.3 tampoco. –

12

virtual se utiliza para declarar un método/propiedad "anulable".

sealed se utiliza para declarar que no se puede heredar la clase.

Así que un método virtual en una clase sellada nunca podría ser anulado, ya que la clase nunca podría ser heredada. Simplemente no tiene sentido.

protected afecta el acceso a un miembro, no lo declara "anulable" como virtual (aunque a menudo se usa de esa manera) y por lo tanto no es contradictorio.

+0

Sí, entiendo eso. Note que no pregunté "¿por qué no compila esto?", Sino que pregunté por qué compila esto. De la misma manera, lo virtual no tiene sentido en una clase sellada, ¿protegido tampoco ve lo que estoy diciendo? – BFree

+0

I * think * el OP se da cuenta de que 'sealed' no tiene un sentido particular con 'virtual' o con' protected'. Se pregunta por qué se permite un elemento que "no tiene sentido", mientras que otro no. –

+0

@ 280Z28 Estoy de acuerdo ... Necesitamos que Skeeter nos explique esto. –

4

No veo una buena razón para esto. El MyMethod protegido se puede llamar desde MyClass, pero nunca se llamará desde una clase derivada (porque MyClass está sellado). La versión virtual también se puede llamar directamente desde MyClass, pero es ilegal que el método tenga una anulación porque no se puede derivar una clase de MyClass ...

2

Una clase sellada puede tener miembros protegidos a través de la herencia . Cuando un método es parte de una clase, no importa cómo llegó ese método allí.

En el primer caso, con el método protegido en la clase sellada, es lo mismo que si la clase sellada heredara un método protegido. Entonces compila.

Por curiosidad, ¿qué es exactamente la advertencia?

+0

La advertencia es: "warning CS0628: 'SimpleTestApp.Class1.foo()': nuevo miembro protegido declarado en clase sellada." –

1

Una clase sellada no puede ser subclasificada, por lo tanto, virtual no es una opción. Por lo tanto, error.

Este primero es un poco tonto pero válido, por lo tanto, advertencia.

2

El error es:

CS0549: 'función' es un nuevo miembro virtual en la clase de sellado 'clase'.

En primer lugar, a pesar del hecho de que no tiene mucho sentido para incluir nuevos protected o virtual miembros de una clase sealed, la CLI¹ sí lo permite. La CLI también permite llamar a miembros de una clase sellada utilizando la instrucción callvirt IL, aunque un compilador podría reemplazarla libremente con la instrucción call.

Actualmente, no puedo encontrar nada en ECMA-334 (Especificación del lenguaje C#) que requiera que el compilador emita el error anterior. Parece que la implementación de Microsoft agregó el error simplemente porque no tiene sentido incluir nuevos miembros virtuales en una clase sellada.

¹La CLI es una máquina virtual, y el compilador de C# emite código de bytes que se ejecuta en él. Casi cualquier concepto que es ilegal en la CLI también es ilegal en C# por esa razón, pero este es un caso en el que C# tiene un poco más (no es que sea un problema).

Editar: Parece que las publicaciones que se marcan están explicando por qué no tiene sentido escribir código como ese en el OP. Pero con respecto a qué regla lo convirtió en un error de compilación, parecen estar equivocados.

0

Supongo que el compilador realiza algunas optimizaciones con clases selladas que son imposibles si tiene un método virtual declarado - "no tener un vtable" parece un candidato probable.

Eso solo es una suposición.

0

Como se selló When applied to a class, the sealed modifier prevents other classes from inheriting from it.

Aquí estoy tratando de explicar que uno por uno :

public sealed class MyClass 
{ 
    protected void MyMethod(){} 
} 

que os da aviso ya que prácticamente se hace no tiene sentido porque después de declarar una clase como sellados no se puede hereda y que su método es protected lo que no puede acceder a él fuera de la clase utilizando su objec t (y ten en cuenta también que no puedes crear una clase hija de este modo así que no puedes usar este método por ese truco también). Así que prácticamente no tiene sentido hacerlo protected así el compilador te da una advertencia pero si lo hace como public o internal, entonces no le dará error porque es útil en ese caso.

ahora la segunda:

public sealed class MyClass 
{ 
    public virtual void MyMethod(){} 
} 

a medida que sellan la clase y ahora está haciendo su método como virtual, de forma indirecta, le está dando una oferta a alguien para anularlo y que puede ser posible sólo por herencia y aquí viene el problema. Que tu clase está sellada por lo que no puedes realizar la herencia con esta clase. Así que con virtual da error.

espero que te ayude a comprender.

para referencia http://msdn.microsoft.com/en-us/library/88c54tsw.aspx

0

Declarar un nuevo miembro protegido implica una intención de compartir ese miembro con las clases descendientes. Una clase sellada no puede tener descendientes, por lo que declarar un nuevo miembro protegido es un poco oxímoron, al igual que declarar un nuevo método virtual en una clase sellada.

En cuanto a por qué virtual produce un error mientras protegido solo produce una advertencia, solo puedo especular que tal vez tiene que ver con el hecho de que los nuevos métodos virtuales requieren que el compilador construya estructuras de datos para el tipo (a vtable). mientras que los nuevos miembros protegidos solo tienen un indicador de acceso establecido, no hay una nueva estructura de datos. Si el compilador tiene prohibido crear un vtable para una clase sellada, ¿qué debería hacer si encuentra un nuevo método virtual? Falla la compilación. Un nuevo método protegido en una clase sellada no tiene sentido pero no requiere que el compilador se aventure en un territorio prohibido.

Cuestiones relacionadas