2010-04-30 14 views
22

Jon's Brain Teaserssobrecargas método de resolución y enigmas de Jon Skeet

Aquí spoilers ...

estoy mirando a la answer a # 1, y tengo que admitir que nunca sabía que esto era el caso en resolución de sobrecarga. Pero por qué es este es el caso. En mi pequeña mente Derived.Foo(int) parece ser la ruta lógica para bajar.

¿Cuál es la lógica detrás de esta decisión de diseño?

BONUS TIME!

¿Este comportamiento es el resultado de la especificación C#, la implementación CLR o el compilador?

+0

Eso es definitivamente un comportamiento extraño! Probablemente diseñaron eso en una tarde de viernes después de demasiada cerveza a la hora del almuerzo. – Etienne

+0

O después de horas de deliberación sobre cuál sería el mejor comportamiento general;) – Skurmedel

+0

¡Creo que viste lo mismo que yo porque acabamos de debatir la respuesta a la misma pregunta! – NibblyPig

Respuesta

14

Este comportamiento es deliberado y cuidadosamente diseñado. La razón es porque esta elección mitiga el impacto de una forma de la falla de clase base frágil.

Lea mi artículo sobre el tema para más detalles.

http://blogs.msdn.com/ericlippert/archive/2007/09/04/future-breaking-changes-part-three.aspx

+0

¡Sabía que habría una razón sólida en algún lado! Entonces (¡para el tiempo de bonificación!) ¿Es esta una especificación de C# o CLR? – gingerbreadboy

+3

@runrunraygun: El CLR no tiene un algoritmo de resolución de sobrecarga; la resolución de sobrecarga es un concepto de lenguaje. El CLR IL solo tiene instrucciones que invocan cualquier referencia de método en una ubicación particular. Entonces esto no puede ser una especificación CLR. Este comportamiento se especifica en la sección de especificación C# 7.6.5.1, el punto que comienza "El conjunto de métodos candidatos se reduce para contener solo los métodos de los tipos más derivados ..." –

-3

el motivo es: rendimiento. llamando a un método virtual toma un poco más de tiempo. llamar a un delegado en un método virtual toma mucho más tiempo y así sucesivamente ....

véase: The cost of method calls

+0

¿De verdad? Si bien la información sobre los costos de las llamadas es muy interesante y sin duda habría influido en una serie de decisiones, no estoy seguro de poder ver un vínculo directo entre los dos problemas. Sí, han optado por lo no virtual como el valor predeterminado donde no está definido para los motivos de rendimiento de la llamada al método, ¿esto realmente impone la resolución de sobrecarga en un grado tal que los hace optar por lo que a mí y a otras personas "no intuitivo"? Todavía no estoy convencido de que esta sea LA razón que lo define, pero agradecida por una respuesta interesante, no obstante. T – gingerbreadboy

+8

Este no es el motivo. –

1

Aquí es una posible explicación:

Cuando el compilador une las llamadas a métodos, el primero colocarlo en la clase que está más abajo en la cadena de herencia (en este caso, la clase Derived). Sus métodos de instancia son verificados y emparejados. El método reemplazado Foo no es un método de instancia de Derived, es un método de instancia de la clase Base.

La razón por la cual podría ser el rendimiento, como propuso Jack30lena, pero también podría ser la forma en que el compilador interpreta la intención del codificador. Es una suposición segura de que el comportamiento previsto del código del desarrollador reside en el código en la parte inferior de la cadena de herencia.

+0

Este es un punto interesante, ¡mira TIEMPO DE BONIFICACIÓN! :) – gingerbreadboy

+0

¿Por "más bajo" te refieres a lo que está más alejado de la clase base? Normalmente describiría lo que estaba más alejado de la base de una cosa como lo "más alto". (Por otra parte, la raíz de un árbol es el nodo más alto del árbol, y eso tampoco tiene sentido ...) Dicho esto, su análisis es correcto; el desarrollador de la clase derivada sabe más que el desarrollador de la clase base, por lo que sus métodos tienen prioridad. –

+0

Estaba pensando en términos de árbol. Lo que es realmente interesante es por qué este tipo de ocultamiento no da como resultado una advertencia. Básicamente, cualquier método de instancia con un parámetro más general ocultará eficazmente la anulación más específica. Sé que este código no es completamente inalcanzable (por Foxfire), pero está oculto de todos modos. Parece que debería producir una advertencia. Además, gracias por verificar mi respuesta, sus artículos fueron útiles. – Audie

-1

La razón es porque es ambiguo. El compilador solo tiene que decidir por uno. Y alguien pensó que el menos indirecto sería mejor (el rendimiento podría ser una razón). Si el desarrollador simplemente escribió:

((Base)d).Foo (i); 

está claro y que le da el resultado esperado.

1

Es un resultado del compilador, examinamos el código IL.

+1

Sí, pero es así por las especificaciones. – configurator

Cuestiones relacionadas