property net example custom attribute asp c# reflection attributes custom-errors

net - reflection c# example



¿Cómo obtengo el miembro al que se aplicó mi atributo personalizado? (4)

Dado que parece haber mucha confusión con respecto a cómo funcionan los marcos de pila y los métodos, aquí hay una demostración simple:

static void Main(string[] args) { MyClass c = new MyClass(); c.Name = "MyTest"; Console.ReadLine(); } class MyClass { private string name; void TestMethod() { StackTrace st = new StackTrace(); StackFrame currentFrame = st.GetFrame(1); MethodBase method = currentFrame.GetMethod(); Console.WriteLine(method.Name); } public string Name { get { return name; } set { TestMethod(); name = value; } } }

El resultado de este programa será:

escoger un nombre

Las propiedades en C # son una forma de azúcar sintáctico. Compilan los métodos getter y setter en el IL, y es posible que algunos lenguajes .NET incluso no los reconozcan como propiedades. La resolución de la propiedad se hace por convención, no hay realmente ninguna regla en la especificación IL.

Ahora, digamos por el momento que tienes una muy buena razón para que un programa quiera examinar su propia pila (y hay muy pocas razones prácticas para hacerlo). ¿Por qué en el mundo querrías que se comportara de forma diferente en cuanto a propiedades y métodos?

Todo el razonamiento detrás de los atributos es que son un tipo de metadatos. Si desea un comportamiento diferente, codifíquelo en el atributo . Si un atributo puede significar dos cosas diferentes dependiendo de si se aplica a un método o propiedad, entonces debe tener dos atributos . Establezca el destino en el primero en AttributeTargets.Method y el segundo en AttributeTargets.Property . Sencillo.

Pero una vez más, caminar en su propia pila para recoger algunos atributos del método de llamada es, en el mejor de los casos, peligroso. En cierto modo, está congelando el diseño de su programa, lo que hace que sea mucho más difícil para alguien ampliarlo o refactorizarlo. Esta no es la forma en que los atributos se usan normalmente. Un ejemplo más apropiado sería algo así como un atributo de validación:

public class Customer { [Required] public string Name { get; set; } }

Entonces su código de validador, que no sabe nada sobre la entidad real que se está transfiriendo, puede hacer esto:

public void Validate(object o) { Type t = o.GetType(); foreach (var prop in t.GetProperties(BindingFlags.Instance | BindingFlags.Public)) { if (Attribute.IsDefined(prop, typeof(RequiredAttribute))) { object value = prop.GetValue(o, null); if (value == null) throw new RequiredFieldException(prop.Name); } } }

En otras palabras, está examinando los atributos de una instancia que le fue entregada pero de los que no necesariamente sabe nada sobre el tipo de. Atributos XML, atributos de contrato de datos, incluso atributos de atributo: casi todos los atributos en .NET Framework se utilizan de esta manera para implementar alguna funcionalidad que sea dinámica con respecto al tipo de instancia pero no con respecto al estado del programa o lo que sucede que está en la pila. Es muy poco probable que realmente tenga el control de esto en el punto donde crea el seguimiento de la pila.

Así que voy a recomendar de nuevo que no uses el enfoque de apilar fichas a menos que tengas una muy buena razón para hacerlo y aún no nos hayas informado. De lo contrario, es probable que te encuentres en un mundo de dolor.

Si es absolutamente necesario (no diga que no lo advertimos), utilice dos atributos, uno que pueda aplicarse a los métodos y otro que pueda aplicarse a las propiedades. Creo que te resultará mucho más fácil trabajar que con un único súper atributo.

Estoy creando un atributo personalizado en C # y quiero hacer diferentes cosas en función de si el atributo se aplica a un método frente a una propiedad. Al principio iba a hacer un new StackTrace().GetFrame(1).GetMethod() en mi constructor de atributo personalizado para ver qué método se llamaba el constructor de atributos, pero ahora no estoy seguro de lo que eso me dará. ¿Qué pasa si el atributo se aplicó a una propiedad? ¿ GetMethod() devolvería una instancia de MethodBase para esa propiedad? ¿Hay alguna manera diferente de obtener el miembro al que se le aplicó un atributo en C #?

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, AllowMultiple = true)] public class MyCustomAttribute : Attribute

Actualización: está bien, podría haber estado haciendo la pregunta incorrecta. Desde dentro de una clase de atributo personalizada, ¿cómo obtengo el miembro (o la clase que contiene el miembro) al que se aplicó mi atributo personalizado? Aaronaught sugirió no subir la pila para encontrar el miembro de la clase al que se aplicó mi atributo, pero ¿de qué otro modo podría obtener esta información desde el constructor de mi atributo?


Los atributos proporcionan metadatos y no saben nada sobre la cosa (clase, miembro, etc.) que están decorando. Por otro lado, la cosa decorada puede solicitar los atributos con los que está decorada.

Si debe saber el tipo de cosa decorada, deberá pasarla explícitamente a su atributo en su constructor.

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, AllowMultiple = true)] public class MyCustomAttribute : Attribute { Type type; public MyCustomAttribute(Type type) { this.type = type; } }


los atributos personalizados se activan mediante un código que llama al método GetCustomAttributes en ICustomAttributeProvider (objeto de reflexión) que representa la ubicación donde se aplica el atributo. Entonces, en el caso de una propiedad, algún código obtendría PropertyInfo para la propiedad y luego llama a GetCustomAttributes sobre eso.

Si desea construir un marco de validación, deberá escribir el código que inspecciona los tipos y miembros para obtener atributos personalizados. Por ejemplo, podría tener una interfaz que le de atributos a implementar para participar en su marco de validación. Podría ser tan simple como lo siguiente:

public interface ICustomValidationAttribute { void Attach(ICustomAttributeProvider foundOn); }

Su código podría buscar esta interfaz en (por ejemplo) un Tipo:

var validators = type.GetCustomAttributes(typeof(ICustomValidationAttribute), true); foreach (ICustomValidationAttribute validator in validators) { validator.Attach(type); }

(presumiblemente recorrería todo el gráfico de reflexión y haría esto para cada ICustomAttributeProvider). Para ver un ejemplo de un enfoque similar en acción en .net FX, puede ver los "comportamientos" de WCF (IServiceBehavior, IOperationBehavior, etc.).

Actualización: .net FX tiene un objetivo general, pero básicamente un marco de interceptación no documentado en forma de ContextBoundObject y ContextAttribute. Puede buscar en la web algunos ejemplos de su uso para AOP.


GetMethod siempre te devolverá el nombre de la función. Si es una propiedad, obtendrá get_PropertyName o set_PropertyName .

Una propiedad es básicamente un tipo de método, por lo que cuando se implementa una propiedad, el compilador crea dos funciones separadas en el MSIL resultante, un método get_ y aa set_. Esta es la razón por la cual en el seguimiento de la pila usted recibe estos nombres.