Want to show your appreciation? Please to my charity.

Saturday, May 28, 2011

Replacement of TypeNode.GetTypeNode() in FxCop 1.36 and Above

I encountered a number of custom rules written for FxCop 1.35 in a project. They need to be upgraded to FxCop 1.36. Those custom rules make extensive use of TypeNode.GetTypeNode() method, which does no longer exist in the FxCop 1.36 and above (including Visual Studio build-in Code Analysis).

As Google returned no useful result, I started to explore the new SDK API for an alternative. I found two ways to get a TypeNode instance.

  • TypeNodes predefined FrameworkTypes class, if the type you want is not there than,
  • ModuleNode.GetType() method with a namespace and type name.

Get an instance of ModuleNode is easy by a location string that I can obtain from a type object, so this sounds like a viable solution:

   1:   return AssemblyNode.GetAssembly(type.Module.Assembly.Location)
   2:      .GetType(Identifier.For(type.Namespace), Identifier.For(type.Name));

Code above works great until I encountered nested types. In the case of nested types, the code above just return null. I have used all different combinations of the name, say for a nested type NestedType in MyNamespace.MyType, in below. None of those worked.

Namespace parameter Name parameter
Namespace MyType+NestedType
Namespace MyType.NestedType
Namespace.MyType NestedType

 

Further investigation found me the method TypeNode.GetNestedType. It turned out that you must get the parent type first, then call that method to get the TypeNode for the nested type. Once this is resolved, I have perfectly working alternative to the missing GetTypeNode in FxCop 1.36. Below are the extension methods to achieve this:

   1:  public static TypeNode GetType(this ModuleNode @this, Type type)
   2:  {
   3:      if (@this == null) { throw new ArgumentNullException("this"); }
   4:      if (type == null) { throw new ArgumentNullException("type"); }
   5:      return GetType(@this, type.DeclaringType, type, Identifier.For(type.Namespace));
   6:  }
   7:   
   8:  private static TypeNode GetType(this ModuleNode @this, Type parent, Type type, Identifier @namespace)
   9:  {
  10:      if (parent == null) return @this.GetType(@namespace,Identifier.For(type.Name));
  11:      var parentType = GetType(@this, parent.DeclaringType, parent, @namespace);
  12:      return parentType.GetNestedType(Identifier.For(type.Name));
  13:  }
  14:   
  15:  public static AssemblyNode GetAssemblyNode(this Type @this)
  16:  {
  17:      if (@this == null) throw new ArgumentNullException("this");
  18:   
  19:      return AssemblyNode.GetAssembly(@this.Module.Assembly.Location);
  20:  }
  21:   
  22:  public static TypeNode GetTypeNode(this Type @this)
  23:  {
  24:      if (@this == null) throw new ArgumentNullException("this");
  25:      return @this.GetAssemblyNode().GetType(@this);
  26:  }

As a side note, if you found yourself calling GetTypeNode with a known type, you should define a static field to improve the performance. Just like what was in the FrameworkTypes class. For example, I have below in my project:

   1:  public static readonly TypeNode CompilerGeneratedAttribute = typeof(CompilerGeneratedAttribute).GetTypeNode();
   2:  public static readonly TypeNode DebuggerNonUserCodeAttribute = typeof(DebuggerNonUserCodeAttribute).GetTypeNode();
   3:  public static readonly TypeNode GeneratedCodeAttribute = typeof(GeneratedCodeAttribute).GetTypeNode();
   4:  public static readonly TypeNode IComponent = typeof(IComponent).GetTypeNode();
   5:  public static readonly TypeNode FrameworkElement = typeof(FrameworkElement).GetTypeNode();

No comments:

Post a Comment