¿Cómo el sistema de resolución de sobrecarga de método decide qué método llamar cuando se pasa un valor nulo?

Entonces, por ejemplo, tienes un tipo como:

public class EffectOptions { public EffectOptions ( params object [ ] options ) {} public EffectOptions ( IEnumerable options ) {} public EffectOptions ( string name ) {} public EffectOptions ( object owner ) {} public EffectOptions ( int count ) {} public EffectOptions ( Point point ) {} } 

Aquí solo doy el ejemplo usando constructores, pero el resultado será el mismo si fueran métodos que no sean de constructor en el tipo en sí, ¿no?

Entonces cuando lo haces:

 EffectOptions options = new EffectOptions (null); 

qué constructor se llamaría, y por qué?

Podría probarlo yo mismo, pero quiero entender cómo funciona el sistema de resolución de sobrecarga (no estoy seguro de que así se llame).

Para conocer las reglas exactas, consulte la especificación de resolución de sobrecarga . Pero brevemente, dice así.

Primero, haz una lista de todos los constructores accesibles .

 public EffectOptions ( params object [ ] options ) public EffectOptions ( IEnumerable options ) public EffectOptions ( string name ) public EffectOptions ( object owner ) public EffectOptions ( int count ) public EffectOptions ( Point point ) 

A continuación, elimine todos los constructores inaplicables . Un constructor aplicable es aquel en el que cada parámetro formal tiene un argumento correspondiente, y el argumento es implícitamente convertible al tipo de parámetro formal. Suponiendo que Point es un tipo de valor, eliminamos las versiones “int” y “Point”. Eso deja

 public EffectOptions ( params object[] options ) public EffectOptions ( IEnumerable options ) public EffectOptions ( string name ) public EffectOptions ( object owner ) 

Ahora, debemos considerar si el que tiene “params” es aplicable en su forma expandida o no expandida . En este caso, es aplicable en ambas formas. Cuando eso sucede, descartamos la forma expandida . Entonces eso deja

 public EffectOptions ( object[] options ) public EffectOptions ( IEnumerable options ) public EffectOptions ( string name ) public EffectOptions ( object owner ) 

Ahora debemos determinar el mejor de los candidatos aplicables. Las reglas de bondad son complicadas, pero la versión corta es que lo más específico es mejor que lo menos específico . La jirafa es más específica que el mamífero, el mamífero es más específico que el animal, el animal es más específico que el objeto.

La versión “objeto” es menos específica que todas, por lo que puede eliminarse. La IEnumerable es menos específica que la versión de object[] (¿ves por qué?) Por lo que también se puede eliminar. Eso deja

 public EffectOptions ( object[] options ) public EffectOptions ( string name ) 

Y ahora estamos estancados. objeto [] no es más ni menos específico que la cadena. Por lo tanto, esto da un error de ambigüedad.

Eso es solo un breve boceto; el verdadero algoritmo de desempate es mucho más complicado. Pero esos son los conceptos básicos.

En este caso, el comstackdor de C # no elegirá ningún constructor y, en su lugar, generará un error. El valor null es legal para varios de los constructores disponibles y no hay suficiente lógica de desempate para elegir uno, por lo que produce un error.

La lógica de resolución de sobrecarga del comstackdor de C # es un proceso complejo, pero una visión general breve (e inherentemente incompleta) de cómo funciona es la siguiente

  • Recoge todos los miembros con el nombre dado
  • Filtra los miembros a aquellos con listas de parámetros que sean compatibles con los argumentos proporcionados y con la accesibilidad adecuada
  • Si los miembros restantes tienen más de un elemento, emplee la lógica de desempate para elegir el mejor de ellos

Los detalles completos se enumeran en la sección 7.4 de la especificación del lenguaje C #. Y estoy seguro de que Eric llegará pronto para dar una descripción mucho más precisa 🙂