2010-11-19 11 views
5

Hay sizeof() y typeof(), pero ¿por qué no un memberinfo() devolviendo una instancia de System.Reflection.MemberInfo para la parte de código seleccionada para ayudar en el código de reflexión.¿Por qué no una función de reflexión memberinfo() para C#

Ejemplo:

Program() 
{ 
     Type t = typeof(Foo); 

     Foo foo = new Foo(); 
     PropertyInfo pi = memberinfo(Foo.Name) as PropertyInfo; 
     // or shall it be like this 
     // PropertyInfo pi = memberinfo(foo.Name) as PropertyInfo; 

     string name = pi.GetValue(foo, null); 
} 

Estoy tratando de entender si hay una razón fundamental por la cual esto podría ser implementado en la especificación C#.

No estoy criticando nada, solo estoy haciendo algunas ilusiones, así que sea amable por favor.

+0

Probablemente podría implementarse fácilmente. Yo también quería algo como esto. Tenga en cuenta que se requeriría una sintaxis alternativa para los métodos, ya que pueden estar sobrecargados, por lo que especificar el nombre solo no sería suficiente en ese caso. – cdhowie

+0

Puede crear algo similar utilizando Expression Trees; esto funciona particularmente bien para propiedades y campos. –

+0

@Bryant ¿tiene un ejemplo o un enlace? – ja72

Respuesta

8

Eric Lippert habla de esto extensamente en su blog

Para citar directamente de ese mensaje:

Justo al lado de la parte superior de mi cabeza, he aquí algunas razones por las cuales {esto no se ha hecho}. (1) ¿Cómo se especifica inequívocamente que se desea una información de método de una implementación de interfaz explícita específica? (2) ¿Qué pasa si la resolución de sobrecarga se hubiera saltado un método en particular porque no es accesible? Es legal obtener información del método de métodos que no son accesibles; los metadatos siempre son públicos, incluso si describen detalles privados. ¿Deberíamos imposibilitar la obtención de metadatos privados, debilitar la función o hacerla posible, y hacer que la información use un algoritmo de resolución de sobrecarga sutilmente diferente que el resto de C#? (3) ¿Cómo se especifica que quiere la información de, por ejemplo, un setter de indexador, o un getter de propiedad, o un sumador de manejador de eventos?

5

Hay un par de elementos que dificultan este tipo de característica. Uno de los principales son los métodos sobrecargados.

class Example { 
    public void Method() {} 
    public void Method(int p1) {} 
} 

Qué MethodInfo haría el siguiente cambio?

var info = memberinfo(Example.Method); 

Como Wesley ha señalado, sin embargo, Eric's Blog tiene la discusión completa sobre este tema.

+1

Su ejemplo está un poco apagado, ya que 'Type.GetMethod()' tampoco funcionaría en este caso ... arroja una 'AmbiguousMatchException'. Si bien existen desafíos sintácticos para implementar 'infoof', definitivamente haría que el código sensible a la reflexión fuera más fácil de mantener. Si 'infoof' es suficientemente valioso en comparación con todas las demás mejoras posibles al lenguaje C# es otra cuestión completamente distinta. – LBushkin

+0

Podría devolver una matriz con todas las sobrecargas. – ja72

+0

@LBushkin no estoy seguro de cómo eso hace que mi ejemplo se apague. Está señalando las dificultades para desambiguar los métodos sobrecargados con la característica hipotética 'memberinfo'. – JaredPar

1

Hay numerosas razones por las cuales la reflexión miembro en tiempo de compilación todavía no se ha implementado en C# - pero la mayoría de ellos básicamente se reducen a opportunity cost - hay muchos otros idiomas características y mejoras que ofrecen más beneficios a más usuarios. También existe la consideración de que una sintaxis infoof podría ser complicada, confusa y, en última instancia, menos poderosa que el uso de reflexión basada en cadenas. Tampoco sería un reemplazo completo para la reflexión ya que en muchos casos los metadatos que se manipulan no se conocen en tiempo de compilación.

Sin embargo, no todo está perdido, hay una serie de trucos que puede emplear para realizar una reflexión ligeramente más segura que aprovecha las capacidades del lenguaje C#. Por ejemplo, podemos aprovechar las expresiones lambda y los árboles de expresión para extraer la información de MemberInfo.Un ejemplo sencillo es:

public static class MethodExt { 
    static MethodInfo MemberInfo(Action d) { 
     return d.Method; 
    } 
    // other overloads ... 
} 

que funciona cuando se pasa de un delegado de acción (no anónimo):

MethodInfo mi = MethodExt.MemberInfo(Object.ToString); 

Una implementación de la anterior utilizando árboles de expresión puede más robusto y flexible, pero también sustancialmente más complicado. Se podría usar para representar el acceso a miembros y propiedades, indexadores, etc.

El problema principal con todos estos enfoques "sofisticados" es que confunden a los desarrolladores que están acostumbrados a ver el código de reflexión tradicional. Tampoco pueden manejar todos los casos, lo que a menudo resulta en una desafortunada mezcla de código de reflexión tradicional y código de árbol de expresión elegante. Personalmente, si bien estas técnicas son interesantes e ingeniosas, probablemente sea mejor evitarlas en el código de producción.

+0

'D' afirma que tiene tiempo de compilación de reflexión! :) – nawfal

0

Yo mismo uso un enfoque que lee el IL de un método anónimo (usando el espacio de nombres Mono.Reflection) y capto la información del último token encontrado en el método anónimo. Esta tiende a ser la única forma de obtener información sobre cosas como add_EventHandler o set_Property o variables locales capturadas. Para obtener propiedades reales, uso árboles de expresiones.

La sintaxis que uso es Reflect.Member<T>.InfoOf<TMember>(Func<T,TMember> memberfunc) donde el miembro se reemplaza con el tipo que me interesa. Es muy detallado, pero le permite a un usuario saber exactamente lo que el código intenta hacer. También tengo Reflect.Member estilos para cosas como estáticos y constructores. Aquí es el fragmento de código relevante ::

internal static MemberInfo GetLastMemberOfType(MethodBase method, MemberTypes memberType) 
    { 
     var instructions = method.GetInstructions(); 
     var operandtype = memberType == MemberTypes.Field ? OperandType.InlineField : OperandType.InlineMethod; 
     for (int i = instructions.Count-1; i > -1 ; i--) 
     { 
      if (instructions[i].OpCode.OperandType == operandtype) 
      { 
       return instructions[i].Operand as MemberInfo; 
      } 
     } 
     return null; 
    } 

¿Sustituye reflexión a partir de cuerdas? Absolutamente no. ¿Hace que mi código sea más seguro mientras estoy refabricando interfaces y qué no? Absolutamente. ¿Se enviará con el producto en el que estoy trabajando? Probablemente no.

Cuestiones relacionadas