How to discover all classes including subclasses with attribute attached at runtime?

85 views Asked by At

I have an attribute that I use to mark certain classes in my solution. I have to check whether this attribute is on objects that are moving around. This check (type.IsDefined(typeof(XmlImmutableAttribute), true);) is being done so often that is is becoming a burden and hurting performance. I have dealt with a similar problem before by finding all the types with the attribute attached and storing them in a HashSet, and checking set.Contains(type); (see my answer here). This is the code I currently have:

public class XmlImmutableAttribute : XmlSerializedAttribute {

    private static readonly HashSet<Type> m_XmlImmutableAttributeTypes; // Set for the quick lookup of types that are marked with the XmlImmutableAttribute

    public XmlImmutableAttribute() {
    }

    static XmlImmutableAttribute() { // 
            m_XmlImmutableAttributeTypes = new HashSet<Type>();
            foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies()) {
                foreach (Type type in assembly.GetTypes()) {
                    if (type.IsDefined(typeof(XmlImmutableAttribute), false)) {
                        m_XmlImmutableAttributeTypes.Add(type);
                    }
                }
            }
    }

    public static bool IsAttachedTo(Type type) { // returns true if the attached type is marked immutable
        return m_XmlImmutableAttributeTypes.Contains(type);
    } 

    public static bool IsAttachedTo<T>() { // returns true if the attached type is marked immutable
        return IsAttachedTo(typeof(T));
    } 
}

The issue is that m_XmlImmutableAttributeTypes only becomes initialized to contain the types that have the attributes directly attached, and non of the types that have been sub classed from the type attached. I assume this is an issue with the check being done in the static constructor of the attribute itself, because when I check type.IsDefined(typeof(XmlImmutableAttribute), false) on a subclass after the static initialization, it returns true. How can I maintain this pattern of predetermining types for increased efficiency, while also having it detect the sub classes with the attribute attached?

2

There are 2 answers

0
Raphaël Althaus On BEST ANSWER

Change

if (type.IsDefined(typeof(XmlImmutableAttribute), false))

to

if (type.IsDefined(typeof(XmlImmutableAttribute), true))

to search in the inheritance chain

0
Nicholas Carey On

I'd probably refactor your attribute to use lazy initialization like this:

public class XmlImmutableAttribute : XmlSerializedAttribute
{

  private static readonly object _syncroot       = new object() ;
  private static HashSet<Type>   _immutableTypes = null ; 
  private static HashSet<Type> ImmutableTypes
  {
    get
    {
      lock ( _syncroot )
      {
        if ( _immutableTypes == null )
        {
          _immutableTypes = new HashSet<Type>(
                              AppDomain
                              .CurrentDomain
                              .GetAssemblies()
                              .SelectMany( a => a.GetTypes() )
                              .Where( t => t.IsDefined( typeof(XmlImmutableAttribute) , true ) )
                              ) ;
        }
      }
      return _immutableTypes ;
    }
  }

  public static bool IsAttachedTo( Type type )
  {
    bool isImmutable = ImmutableTypes.Contains(type) ;
    return isImmutable ;
  }

  public static bool IsAttachedTo<T>()
  { // returns true if the attached type is marked immutable
    return IsAttachedTo( typeof( T ) );
  }

}

If that doesn't work, another approach would be to do cache the lookups, thus:

public class XmlImmutableAttribute : XmlSerializedAttribute
{

  private static readonly Dictionary<Type,bool> ImmutableTypes = new Dictionary<Type,bool>() ;

  public static bool IsAttachedTo( Type type )
  {
    if ( type == null ) throw new ArgumentNullException("type");
    bool isImmutable ;
    lock ( ImmutableTypes )
    {
      bool found = ImmutableTypes.TryGetValue(type, out isImmutable ) ;
      if ( !found )
      {
        isImmutable = type.IsDefined(typeof(XmlImmutableAttribute),true) ;
        ImmutableTypes.Add(type,isImmutable) ;
      }
    }
    return isImmutable ;
  }

  public static bool IsAttachedTo<T>()
  { // returns true if the attached type is marked immutable
    return IsAttachedTo( typeof(T) );
  }

}