2010-01-11 18 views
17

Estoy luchando con una resolución de sobrecarga de método extraña, al menos para mí, de .net. He escrito una pequeña muestra para reproducir el problema:Método de resolución de sobrecarga comportamiento inesperado

class Program 
{ 
    static void Main(string[] args) 
    { 
     var test = new OverloadTest(); 
     test.Execute(0); 
     test.Execute(1); 

     Console.ReadLine(); 
    } 
} 

public class OverloadTest 
{ 
    public void Execute(object value) 
    { 
     Console.WriteLine("object overload: {0}", value); 
    } 

    public void Execute(MyEnum value) 
    { 
     Console.WriteLine("enum overload: {0}", value); 
    } 
} 

public enum MyEnum 
{ 
    First = 1, Second = 2, Third = 3 
} 

imprimirá:

enum overload: 0 
object overload: 1 

Básicamente, la sobrecarga de llamada es diferente en función del valor (0, 1) en lugar del tipo de datos determinado .

¿Podría alguien explicar?

actualización

debería haber señalado que hay un comportamiento diferente entre C# 2 y C# 3

Do((long)0) => object overload //C# 2 
Do((long)0) => enum overload //C# 3 

Respuesta

16

Sí - la constante 0 es implícitamente convertible a cualquier tipo de enumeración. La constante 1 es solo explícitamente convertible al tipo enum. Ambos son implícitamente convertibles a object (a través del boxeo), pero la conversión a la enumeración se prefiere donde esté disponible.

Tenga en cuenta que esto tiene nada para hacer con qué valores define la enumeración. La conversión para cualquier valor que no sea cero es explícita si coincide con un valor en la enumeración o no. Es solo un caso especial para el valor 0, que hace que otro código sea más simple (particularmente cuando se trata de banderas). No tengo las especificaciones a mano para encontrar la referencia, me temo.

Extraño de la bonificación: debido a un error en el compilador de MS (que nunca se solucionará - se rompería la compatibilidad con versiones anteriores) en realidad es various zero constants, no solo un número entero. Así que Execute(0d) y Execute(0m) convertirá un doble y un decimal a la enumeración también. No funciona para cada constante cero - depende de la naturaleza exacta del código fuente. Es todo muy extraño - siga el enlace donde Eric Lippert revela todo ...

+0

Eso es muy extraño. Hubiera esperado que no compilara en absoluto, porque las dos llamadas separadas a Execute son ambiguas. 0 y 1 son int, por lo que es igualmente válido llamar a la sobrecarga del objeto así como a la sobrecarga de MyEnum. – Nick

+0

no lo sabía. ¿Por qué 0 es implícitamente convertible a cualquier tipo de enumeración? en el ejemplo aquí, 0 no es un valor válido. si algo no tiene sentido para mi línea de pensamiento, eso no necesariamente significa mucho (como se indicó hace 1 minuto);) – hackerhasid

+0

@statichippo: Es útil en algunos casos, como después de realizar operaciones aritméticas en bits en banderas. @Nick: ambos métodos son * aplicables *, pero la conversión de 0 a enum es "mejor que" la conversión de 0 a objeto por las reglas de la especificación C# ... razón por la cual se llama esa sobrecarga. –

-1

una enumeración es sólo asignada a un int (por defecto). 0 no se asigna a su Enum para que se use la sobrecarga que toma un objeto. 1 se asigna a su enumeración para que se use la sobrecarga de Enum.

usted puede hacer esto:

Execute((object) 1); 

a la salida

sobrecarga de objeto: 1

+2

Parece que los resultados son en realidad lo contrario de lo que cabría esperar. La sobrecarga de enum está siendo golpeada por 0 y no por 1. – mkedobbs

+0

Acabo de revisar esto y me di cuenta de que había leído mal la publicación. Pensé que 0 estaba llamando "objeto" y 1 estaba llamando "enum". ¡Tendré que investigar esto porque eso no tiene mucho sentido! – hackerhasid

+0

@statichippo: Tiene mucho sentido cuando observa las especificaciones y las conversiones disponibles :) –

0

Estoy de acuerdo con la respuesta de Jon Skeet - refiérase a su publicación (arriba) el 11 de enero a las 17:32. para ampliar aún más, por favor refiérase a C# lenguaje de especificación - página: 110

6.1.3 conversiones de enumeración implícitos Una conversión de enumeración implícita permite la decimal-entero-literal 0 que ser convertido a cualquier enum de tipo y a cualquier tipo nullable cuyo tipo subyacente sea un tipo enum. En el último caso, la conversión se evalúa convirtiendo al tipo de enumeración subyacente y ajustando el resultado (§4.1.10).

Todavía hay un problema:

la adición de la declaración:

test.Execute (-0,0); // sobrecarga objeto: 0

mientras se añade el siguiente:

test.Execute (0,0); // sobrecarga de enumeración: 0

Jacques Colmenero EA [email protected]

Cuestiones relacionadas