simplificado de this question y se deshizo de posible afectar a LINQPad (sin offsensive), una aplicación de consola simple como esto:grupo método implícito Gotcha conversión (parte 2)
public class Program
{
static void M() { }
static void Main(string[] args)
{
Action a = new Action(M);
Delegate b = new Action(M);
Console.WriteLine(a == b); //got False here
Console.Read();
}
}
Los resultados "falsos" de la operadora ceq
en CIL del código anterior (visite la pregunta original para más detalles). Entonces mis preguntas son:
(1) ¿Por qué ==
se está traduciendo como ceq
en lugar de call Delegate Equals
?
Aquí no me importa la (des) envoltura entre delegado y acción. Por último, al evaluar a == b
, a es de tipo Action
mientras que b es Delegate
. De la especificación:
7.3.4 resolución sobrecarga operador binario
una operación del op y forma x, donde op es un operador binario sobrecargable, x es una expresión de tipo X, e Y es una expresión de tipo Y, se procesa de la siguiente manera:
• Se determina el conjunto de operadores definidos por el usuario posibles proporcionados por X e Y para el operador operativo op (x, y). El conjunto consiste en la unión de los operadores candidatos proporcionados por X y los operadores candidatos proporcionados por Y, cada uno determinado utilizando las reglas del §7.3.5. Si X e Y son del mismo tipo, o si X e Y se derivan de un tipo de base común , los operadores candidatos compartidos solo se producen en el conjunto establecido una vez.
• Si el conjunto de candidatos de operadores definidos por el usuario no está vacío, se convierte en el conjunto de operadores candidatos para la operación . De lo contrario, las implementaciones del operador binario predefinido , incluidos sus formularios levantados, se convierten en el conjunto de operadores candidatos para la operación. Las implementaciones predefinidas de un operador dado se especifican en la descripción del operador (§7.8 a §7.12).
• Las reglas de resolución de sobrecarga de §7.5.3 se aplica al conjunto de los operadores de candidatos para seleccionar el mejor operador con respecto a la lista de argumentos (x, y), y esto se convierte en operador el resultado de la proceso de resolución de sobrecarga. Si la resolución de sobrecarga no selecciona un único mejor operador, se produce un error de tiempo de enlace.
operadores definidos por el usuario7.3.5 candidatos
Dado un tipo T y un operador op operación (A), donde op es un operador sobrecargable y A es una lista de argumentos, el conjunto de los operadores definidos por el usuario candidatos provisto por T para el operador op (A) se determina de la siguiente manera:
• Determine el tipo T0. Si T es un tipo anulable, T0 es su tipo subyacente, de lo contrario T0 es igual a T.
• Para todas las declaraciones op operador en T0 y todas levantadas formas de dichos operadores, si al menos un operador es aplicable (§7.5.3.1) con respecto a la lista de argumentos A, entonces el conjunto de operadores candidatos consta de todos los operadores aplicables en T0.
• De lo contrario, si T0 es un objeto, el conjunto de operadores candidatos está vacío.
• De lo contrario, el conjunto de los operadores candidatos proporcionados por T0 es el conjunto de los operadores candidatos proporcionados por la clase base directa de T0, o la clase base efectiva de T0 T0 si es un parámetro de tipo.
De la especificación, A y B tienen una misma clase base Delegate
, obviamente, la regla operador ==
definido en Delegate
debe aplicarse aquí (el operador == invoca esencialmente Delegate.Equals). Pero ahora parece que la lista de candidatos de los operadores definidos por el usuario está vacía y, por último, se aplica Object ==
.
(2) ¿Debería (Does) el código FCL obedecer la especificación del lenguaje C#? Si no, mi primera pregunta no tiene sentido porque algo es tratado especialmente. Y luego podemos responder todas estas preguntas usando "oh, es un tratamiento especial en FCL, pueden hacer algo que nosotros no podemos. La especificación es para programadores externos, no seas tonto".
Es por eso que es mejor usar 'Equals' cuando se espera la semántica del tipo de valor. Debido a (potencialmente) sobrecargas de operador rotas. – Groo
@Groo: Exacto. Y, por cierto, recibí una advertencia de compilación para el código en la pregunta 'Posible comparación de referencia involuntaria; para obtener una comparación de valores, echa el lado derecho para escribir 'System.Action'. –
Definitivamente tiene que ver con el trato especial de los delegados en general, ya que intentar lo mismo con una jerarquía de clases definida por el usuario llama al método '==' personalizado – AakashM