2009-04-05 16 views
30

Decir que tengo dos versiones sobrecargadas de un método de C#:C#: pasar el método nulo a sobrecargado, ¿qué método se llama?

void Method(TypeA a) { } 
void Method(TypeB b) { } 

que llamo el método con:

Method(null); 

Qué sobrecarga del método se llama? ¿Qué puedo hacer para garantizar que se llame a una sobrecarga en particular?

+0

otro para estar al tanto de los métodos está sobrecargado, donde al menos un método que utiliza la palabra clave params. –

Respuesta

67

Depende de TypeA y TypeB.

  • Si exactamente una de ellas es aplicable (por ejemplo, no hay conversión de null a TypeB porque es un tipo de valor, pero TypeA es un tipo de referencia) y luego se hizo la llamada a la aplicable.
  • De lo contrario, depende de la relación entre TypeA y TypeB.
    • Si hay una conversión implícita TypeA-TypeB pero no la conversión implícita TypeB-TypeA entonces se usará la sobrecarga usando TypeA.
    • Si hay una conversión implícita TypeB-TypeA pero no la conversión implícita TypeA-TypeB entonces se usará la sobrecarga usando TypeB.
    • De lo contrario, la llamada es ambigua y no podrá compilarse.

Véase la sección 7.4.3.4 de la especificación C# 3.0 para las modalidades.

Aquí hay un ejemplo de que no es ambiguo. Aquí TypeB deriva de TypeA, lo que significa que hay una conversión implícita de TypeB a TypeA, pero no al revés. Así, la sobrecarga de uso de TypeB se utiliza:

using System; 

class TypeA {} 
class TypeB : TypeA {} 

class Program 
{ 
    static void Foo(TypeA x) 
    { 
     Console.WriteLine("Foo(TypeA)"); 
    } 

    static void Foo(TypeB x) 
    { 
     Console.WriteLine("Foo(TypeB)"); 
    } 

    static void Main() 
    { 
     Foo(null); // Prints Foo(TypeB) 
    } 
} 

En general, incluso en la cara de una llamada de otra manera ambigua, para asegurarse de que se utiliza una sobrecarga en particular, simplemente fundido:

Foo((TypeA) null); 

o

Foo((TypeB) null); 

Tenga en cuenta que si se trata de la herencia en las clases que declaran (es decir una clase está sobrecargando un método declarado por su clase base) que está en un todo otro problema, y ​​usted ne ed para lanzar el objetivo del método en lugar del argumento.

+0

@Jon: ¿Por qué es el comportamiento como se describe en el caso de que una conversión implícita esté disponible? Prefiero haber esperado todo lo contrario. ¿Es solo una cuestión de definición? –

+2

@divo: Definitivamente es una decisión de diseño, pero probablemente la razón detrás es que el método TypeB es más o menos un caso especializado del método TypeA. Quiero decir, para cada arg válido, por defecto TypeA se emparejará a menos que se sepa que el objeto es TypeB. Este comportamiento para null garantiza esta coherencia. –

+0

Mehrdad tiene razón: si puede convertir de TypeB a TypeA, TypeB es más específico que TypeA, por lo que se elegirá con preferencia. –

1

ambigous call. (error de tiempo de compilación).

+0

hola, Intenté seguir la muestra y no obtuve el error de compilación; ¿Alguna idea de por qué? clase Programa { void test1 (ICollection a) { Console.WriteLine ("test1-ICollection"); } void test1 (IList { Console.WriteLine ("test1-List"); } static void Main (cadena [] args) { Programa p = new Programa(); p.test1 (null); Console.ReadKey(); }} –

+0

pero me dio error de compilación cuando cambié una de las sobrecargas para aceptar un parámetro de tipo IComparer clase del Programa { vacío test1 (IList a) { Console.WriteLine ("test1- Lista"); } void test1 (IComparer a) { Consola.WriteLine ("test1-IComparer"); } static void Main (cadena [] args) { Programa p = new Programa(); p.test1 (null); Console.ReadKey(); } } –

8

Jon Skeet ha dado una respuesta completa, pero desde el punto de vista del diseño no debe depender de los casos de esquina de la especificación del compilador. Si nada más, si tiene que buscar lo que hace antes de escribirlo, la siguiente persona que intente leerlo tampoco sabrá qué es lo que hace. No es mantenible.

Las sobrecargas están ahí por conveniencia, y dos sobrecargas diferentes con el mismo nombre deberían hacer lo mismo. Si los dos métodos hacen cosas diferentes, cambie el nombre de uno o ambos.

Es más habitual que un método sobrecargado tenga variantes con números variables de parámetros, y para la sobrecarga con menos parámetros para proporcionar valores predeterminados razonables.

p. Ej. string ToString(string format, System.IFormatProvider provider) tiene la mayoría de los parámetros,
string ToString(System.IFormatProvider provider) suministra un formato predeterminado y
string ToString() suministra un formato predeterminado y el proveedor,

+0

No veo su punto acerca de las sobrecargas. Es cierto que las sobrecargas deberían hacer lo mismo, pero pueden hacerlo de diferentes maneras. Es por eso que quieres sobrecargas. El número de argumentos es irrelevante, y puede ser el mismo o diferente (por ejemplo: los diversos métodos Convert). Acerca de las características del compilador: según el nivel de habilidad de la siguiente persona, cualquier cosa puede ser un «caso de esquina». Siempre que su diseño tenga sentido y funcione de manera intuitiva, cumple su función. Eso puede requerir una cuidadosa consideración del tiempo de diseño, no tanto cuando la clase se usa más adelante. –

+0

Creo que lo que está diciendo es que el uso más común de las sobrecargas es realizar alguna función en datos que pueden incluir diferentes tipos o pueden incluir más o menos parámetros. De hecho, he escrito un puñado de sobrecargas donde la que tiene menos parámetros en realidad tiene todos los mismos datos (cadenas) en menos piezas dispares. En ese caso, llaman a la sobrecarga superior después de separar las piezas y proporcionarlas de nuevo. –

0

Una solución sencilla es crear otro método con la firma de:

void Method() { } 

o mejor para actualizar la firma en uno de los métodos a ser:

void Method(TypeB b = null) { } 

y luego llamar i t como tan:

Method(); 

En tiempo de compilación el valor null tiene tipo por lo que el compilador no puede hacerlo coincidir con una de las firmas de métodos. En el tiempo de ejecución, cualquier variable que pueda resolverse en null seguirá escribiéndose y por lo tanto no causará ningún problema.

3

Jon Skeet ya respondió qué sobrecarga se elige de manera predeterminada, pero si desea asegurarse de que se llame a una sobrecarga en particular, a menudo es mejor usar parámetros con nombre que el molde.

Si usted tiene:

void Method(TypeA a) { } 
void Method(TypeB b) { } 

se le puede llamar Method(a: null); o Method(b: null);

Cuestiones relacionadas