I want to access the properties of a class from the attribute class by using reflection. Is it possible?
For example:
class MyAttribute : Attribute { private void AccessTargetClass() { // Do some operations } } [MyAttribute] class TargetClass { }
A popular eye drop 'Can-C' containing N-alpha-acetylcarnosine (NAC) claims to reduce, reverse and slow the development of senile cataract. It was developed and is patented by Professor Babizhayev, a bio-physicist and Executive Director of Innovative Vision Products (IVP) [1].
SAFE FOR HUMANS AND DOGS - Can-C is the first and only patented NAC eye drop that uses the exact formula proven effective in both animal and human trials, offering a non-invasive alternative to cataract surgery. EVERY BLINK HYDRATES and lubricates the eye and cornea.
Can-C's ingredients help to soothe and rejuvenate tired eyes, help with macular degeneration, cataracts, and other age-related eye disorders. Can-C eye drops for cataracts contain lubricants, an antioxidant and an anti-glycating agent, N-Acetyl-Carnosine (NAC).
The main ingredient of Can-C™ NAC eye drops is N-acetylcarnosine (NAC), a special analogue of di-peptide carnosine, a naturally occurring anti-oxidant nutrient. NAC is extremely effective at 'mopping up' free radicals, which accelerate aging in the body, including the growth of cataracts.
There are cases where you can't rely on the calling code to pass a type reference.
Below is a solution I cooked up to solve this problem. It's a bit of a shot-gun approach, but it does work...
using System; using System.Reflection; using System.Collections.Generic; using System.Linq; using System.Diagnostics; namespace Ethica.Reflection { /// <summary> /// Helps in discovery of the target of an Attribute /// </summary> /// <typeparam name="TAttribute">An Attribute derived type</typeparam> /// <remarks> /// The .NET framework does not provide navigation from attributes back to their targets, principally for the reason that /// in typical usage scenarios for attributes, the attribute is discovered by a routine which already has a reference to a /// member type. /// /// There are, however, bona-fide cases where an attribute needs to detect it's target - an example is a localizable sub-class of the /// DescriptionAttribute. In order for the DescriptionAttribute to return a localized string, it requires a resource key and, ideally, /// a type reference as the base-key for the ResourceManager. A DescriptionAttribute could not provide this information without /// a reference to it's target type. /// /// Note to callers: /// /// Your Attribute-derived class must implement Equals and GetHashCode, otherwise a run-time exception will occur, since this class /// creates a dictionary of attributes in order to speed up target lookups. /// </remarks> public static class AttributeTargetHelper<TAttribute> where TAttribute : Attribute { /// <summary> /// Map of attributes and their respective targets /// </summary> private static Dictionary<TAttribute, object> targetMap; /// <summary> /// List of assemblies that should not be rescanned for types. /// </summary> private static List<string> skipAssemblies; /// <summary> /// Adds an attribute and it's target to the dictionary /// </summary> /// <param name="attribute"></param> /// <param name="item"></param> private static void Add(TAttribute attribute, object item) { targetMap.Add(attribute, item); } /// <summary> /// Scans an assembly for all instances of the attribute. /// </summary> /// <param name="assembly"></param> private static void ScanAssembly(Assembly assembly) { const BindingFlags memberInfoBinding = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance; if (!skipAssemblies.Contains(assembly.FullName)) { skipAssemblies.Add(assembly.FullName); Debug.WriteLine("Loading attribute targets for " + typeof(TAttribute).Name + " from assembly " + assembly.FullName); foreach (TAttribute attr in assembly.GetCustomAttributes(typeof(TAttribute), false)) Add(attr, assembly); foreach (Type type in assembly.GetTypes()) { foreach (TAttribute attr in type.GetCustomAttributes(typeof(TAttribute), false)) Add(attr, type); foreach (MemberInfo member in type.GetMembers(memberInfoBinding)) { foreach (TAttribute attr in member.GetCustomAttributes(typeof(TAttribute), false)) Add(attr, member); if (member.MemberType == MemberTypes.Method) foreach (var parameter in ((MethodInfo)member).GetParameters()) foreach (TAttribute attr in parameter.GetCustomAttributes(typeof(TAttribute), false)) Add(attr, parameter); } } } foreach (var assemblyName in assembly.GetReferencedAssemblies()) { if (!skipAssemblies.Contains(assemblyName.FullName)) ScanAssembly(Assembly.Load(assemblyName)); } } /// <summary> /// Returns the target of an attribute. /// </summary> /// <param name="attribute">The attribute for which a target is sought</param> /// <returns>The target of the attribute - either an Assembly, Type or MemberInfo instance.</returns> public static object GetTarget(TAttribute attribute) { object result; if (!targetMap.TryGetValue(attribute, out result)) { // Since types can be loaded at any time, recheck that all assemblies are included... // Walk up the stack in a last-ditch effort to find instances of the attribute. StackTrace stackTrace = new StackTrace(); // get call stack StackFrame[] stackFrames = stackTrace.GetFrames(); // get method calls (frames) // write call stack method names foreach (StackFrame stackFrame in stackFrames) { Console.WriteLine(stackFrame.GetMethod().Name); // write method name ScanAssembly(stackFrame.GetMethod().GetType().Assembly); } if (!targetMap.TryGetValue(attribute, out result)) throw new InvalidProgramException("Cannot find assembly referencing attribute"); } return result; } /// <summary> /// Static constructor for type. /// </summary> static AttributeTargetHelper() { targetMap = new Dictionary<TAttribute, object>(); // Do not load any assemblies reference by the assembly which declares the attribute, since they cannot possibly use the attribute skipAssemblies = new List<string>(typeof(TAttribute).Assembly.GetReferencedAssemblies().Select(c => c.FullName)); // Skip common system assemblies skipAssemblies.Add("System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"); skipAssemblies.Add("System.Security, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"); skipAssemblies.Add("System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"); skipAssemblies.Add("System.Data.SqlXml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"); skipAssemblies.Add("System.Configuration, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"); skipAssemblies.Add("System.Numerics, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"); // Scan the entire application ScanAssembly(Assembly.GetEntryAssembly()); } } /// <summary> /// Extends attributes so that their targets can be discovered /// </summary> public static class AttributeTargetHelperExtension { /// <summary> /// Gets the target of an attribute /// </summary> /// <typeparam name="TAttribute"></typeparam> /// <param name="attribute">The attribute for which a target is sought</param> /// <returns>The target of the attribute - either an Assembly, Type or MemberInfo instance.</returns> public static object GetTarget<TAttribute>(this TAttribute attribute) where TAttribute : Attribute { return AttributeTargetHelper<TAttribute>.GetTarget(attribute); } } }
Not directly, but in order for the attribute to do anything, you already must have a handle to the type/member and call its GetCustomAttributes
method, so you can simply pass it in from there:
class MyAttribute : Attribute { public void DoSomethingWithDeclaringType(Type t) { } }
Using it like so:
Type classType = typeof(MyClass); object[] attribs = classType.GetCustomAttributes(typeof(MyAttribute), true); if(attribs.Length > 0) { ((MyAttribute)attribs[0]).DoSomethingWithDeclaringType(classType); }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With