Todos sabemos que las propiedades en C # se compilan con métodos antiguos simples y reales. Pero a diferencia del método (-group) s, no se pueden dar como argumentos a otros métodos que esperan un delegado como a Func<T>
o Action<T>
(getter y setter). ¿Hay algo especial que lo prohíba, o es solo una característica que no vino "gratis" cuando los grupos de métodos se convirtieron implícitamente en delegados?
Código de ejemplo:
public class MyClass
{
public static int X { get; set; }
}
private static void Foo<T>(Func<T> f)
{
Console.WriteLine(f());
}
private static void Bar<T>(Action<T> f)
{
f(default(T));
}
private static void Test()
{
// neither of these lines compile, even with an explicit type-cast.
Foo(MyClass.X);
Bar(MyClass.X);
}
Si tuviera que adivinar, diría que no valía la pena resolver el problema sintáctico de diferenciar entre invocaciones y referencias a la propiedad en sí, cuando simplemente podemos hacer la falta adicional de escritura () => MyClass.X
o x => MyClass.X = x
.
c#
properties
delegates
sara
fuente
fuente
set
es unAction
yget
es unFunc
por ejemplodelegate {return SomeProperty}
pasa getter;delegate(YourType value) {SomeProperty = value}
pasa setter. Si solo necesita pasar uno o dos lugares, esta es una forma abreviada de los métodos ajustados que de otro modo crearía.Interface
con esa propiedad y cambiar la firma del método llamado para tomar esa interfaz como parámetro.Respuestas:
El problema es que "MyClass.X" tiene un significado bien definido, que es llamar al captador en la propiedad "X". Lo importante a tener en cuenta es que, aunque se llama a un método, no se requieren paréntesis.
Por otro lado, cuando se llama a un método regular, como cuando se llama "Foo" en su código de ejemplo, se requieren corchetes para indicar que el método debe ejecutarse. Si desea pasar una referencia a un método, entonces excluiría los corchetes (vea el ejemplo a continuación).
Esto significa que no hay ambigüedad cuando se hace referencia a un método, ya sea que lo esté ejecutando inmediatamente (pasando cualquier argumento que requiera e incluyendo paréntesis) o que esté pasando el método como argumento (sin paréntesis).
Con un getter o setter de propiedad, sin paréntesis ya significa "ejecutar getter / setter inmediatamente". Si el getter / setter de propiedad también se puede pasar como un grupo de métodos, a veces "x.Name" significaría "ejecutar el getter de Name ahora" y a veces significaría "pasar el getter de Name como un grupo de métodos". Si bien es posible cambiar el compilador para desambiguar en función de si "x.Name" parece pasar a una función que espera una cadena (en cuyo caso se ejecutará el getter) o si parece que se pasa a una función que espera un Func <string> (en cuyo caso el captador se pasaría como un grupo de métodos), el equipo del lenguaje C # intenta evitar este tipo de escenarios potencialmente confusos.
fuente
No es posible debido a los fundamentos de cómo funciona la gramática y el compilador.
Las expresiones se evalúan "de abajo hacia arriba", lo que significa que la expresión
MyClass.X
evalúa su valor int antes de que este resultado se alimente como argumento de la función. Su propuesta parece sugerir que el contexto, el tipo de parámetro, podría dirigir si la expresión debe interpretarse como una invocación getter o como una referencia al método getter en sí. Esto no es posible hacerlo de una manera no ambigua. ¿Qué pasa si el tipo de propiedad en sí es unFunc
oAction
? ¿Y cómo sevar x = MyClass.X
interpretará? ¿Qué pasa si el método tiene sobrecargas con unoint
oFunc
oAction
parámetros?Para resolver estas ambigüedades necesita una distinción a nivel de sintaxis, por ejemplo, un operador con soporte especial en la gramática como el
typeof
operador, por ejemplo:Pero esto será muy problemático para una función con un beneficio tan limitado.
fuente
Foo.Do()
es decir, la invocación yFoo.Do
ser el delegado está bien.Foo.X
ser confuso es la propiedad, así como el delegado getter y el delegado setter dependiendo de las diferencias de contexto sutiles . Las buenas características que no son abrumadoramente buenas ni siquiera entran en C #, esto parece ser realmente malo. Si quieres escribir un código corto, prueba Perl.Ya existe una manera de expresar claramente cuál necesita en C #, no veo el problema.
fuente