¿Cómo puede haber ambigüedad entre un captador de propiedades y un método con un argumento?

No puedo creer que nunca haya visto esto antes, pero ¿por qué recibo un error de comstackción para este código?

public class Main { public Main() { var ambiguous = new FooBar(1); var isConfused = ambiguous.IsValid; // this call is ambiguous } } public class FooBar { public int DefaultId { get; set; } public FooBar(int defaultId) { DefaultId = defaultId; } public bool IsValid { get { return DefaultId == 0; } } public bool IsValid(int id) { return (id == 0); } } 

Aquí está el mensaje de error:

Ambigüedad entre ‘FooBar.IsValid’ y ‘FooBar.IsValid (int)’

¿Por qué es esto ambiguo?

Estoy pensando que hay dos razones por las que no debería ser ambiguo:

  1. No hay parentesis después de IsConfused .
  2. No hay argumento int para IsConfused .

¿Dónde está la ambigüedad?

El error es porque es ambiguo ya que se declara usando var . Podría ser:

 bool isConfused = ambiguous.IsValid; 

O:

 Func isConfused = ambiguous.IsValid; 

Usar var requiere que el comstackdor pueda inferir el significado exacto, y en este caso, hay dos posibilidades.

Sin embargo, si elimina la var , aún obtendrá un error (diferente), ya que no puede tener dos miembros con el mismo nombre, uno por propiedad y otro por método.

Es confuso recibir ese mensaje en particular, pero no es legal tener dos miembros con el mismo nombre (excepto la sobrecarga de métodos). Aquí su propiedad y método tienen el mismo nombre. Esta es la misma razón por la que no puede tener una propiedad y una clase interna con el mismo nombre. Los campos, las propiedades, los métodos y las clases internas son todos miembros del tipo adjunto y deben tener nombres únicos.

Obtendrías un error de que “FooBar ya contiene una definición para IsValid”

Al principio, puede parecer que el comstackdor siempre podría averiguar si está llamando al método o usando la propiedad; después de todo, el método tiene paréntesis y no la propiedad.

Sin embargo, eso no se sostiene. Puedes usar un método sin los paréntesis:

 void Foo() { ... } void Bar(Action action) { ... } Bar(Foo); 

Y puedes usar una propiedad entre paréntesis:

 Action MyProperty { get; set; } MyProperty(); 

La única forma de asegurarse de que no haya ambigüedad es no permitir tener un método y una propiedad con el mismo nombre.