2016-10-13 2 views
1

Ich habe einen Typ Typ, die ich eine Assembly für abgeleitete Typen durchsuchen möchte.So implementieren Sie IsAssignableFrom mit Mono.Cecil

Ich versuche Mono.Cecil zu verwenden, um die Baugruppe aus Leistungsgründen vorzuscannen. Das Scannen und Laden aller Assemblys dauert zu lange, und es wurde vorgeschlagen, dass cecil viel schneller einen Prescan durchführen kann, da nur ein Bruchteil der verfügbaren Assemblys passende Typen aufweist.

Bis jetzt habe ich die unten, die nur für Schnittstellen funktioniert.

private static IEnumerable<Type> MatchingTypesFromDll<TParent>(string dllPath) 
    { 
     var type = typeof(TParent); 
     if (!type.IsInterface) 
      throw new Exception("Only interfaces supported"); 
     try 
     { 

      var assDef = Mono.Cecil.AssemblyDefinition.ReadAssembly(dllPath); 
      var types = assDef.Modules.SelectMany(m => m.GetTypes()); 
      if (types.Any(t => t.Interfaces.Any(i=>i.FullName == type.FullName))) 
      { 
       var assembly = Assembly.LoadFrom(dllPath); 
       return assembly 
        .GetExportedTypes() 
        .Where(TypeSatisfies<TParent>); 
      } 
      else 
      { 
       return new Type[] {}; 
      } 
     } 
     catch (Exception e) 
     { 
      return new Type[] { }; 
     } 

    } 

    private static bool TypeSatisfies<TParent>(Type type) 
    { 
     return typeof (TParent).IsAssignableFrom(type) 
    && !type.IsAbstract 
    && !type.IsInterface; 
    } 

Wie könnte ich dies auch für Basisklassen erweitern?

+0

Was meinst du mit 'Normal ', wenn Sie sich auf eine Klasse? – Igor

+0

Ich meine nicht eine Schnittstelle. – bradgonesurfing

+0

Die Formulierung "normale Klassen" wurde in "Basisklassen" geändert – bradgonesurfing

Antwort

1

ist die Hauptfunktion

private static IEnumerable<Type> MatchingTypesFromDll<TBaseType>(string dllPath) 
{ 
    var type = typeof(TBaseType); 
    try 
    { 
     var hasTypes = Mono.Cecil.AssemblyDefinition 
      .ReadAssembly(dllPath) 
      .Modules 
      .Any 
      (m => 
      { 
       var td = m.Import(type).Resolve(); 
       return m.GetTypes().Any(t => td.IsAssignableFrom(t)); 
      }); 

     if (hasTypes) 
     { 
      var assembly = Assembly.LoadFrom(dllPath); 
      return assembly 
     .GetExportedTypes() 
     .Where(TypeSatisfies<TBaseType>); 
     } 
     else 
     { 
      return new Type[] {}; 
     } 
    } 
    catch (Exception) 
    { 
     return new Type[] { }; 
    } 

} 

und die Unterstützung Mono.Cecil Code ist, wo IsAssignableFrom definiert geändert werden soll unter

static internal class TypeDefinitionExtensions 
{ 
    /// <summary> 
    /// Is childTypeDef a subclass of parentTypeDef. Does not test interface inheritance 
    /// </summary> 
    /// <param name="childTypeDef"></param> 
    /// <param name="parentTypeDef"></param> 
    /// <returns></returns> 
    public static bool IsSubclassOf(this TypeDefinition childTypeDef, TypeDefinition parentTypeDef) => 
     childTypeDef.MetadataToken 
      != parentTypeDef.MetadataToken 
      && childTypeDef 
     .EnumerateBaseClasses() 
     .Any(b => b.MetadataToken == parentTypeDef.MetadataToken); 

    /// <summary> 
    /// Does childType inherit from parentInterface 
    /// </summary> 
    /// <param name="childType"></param> 
    /// <param name="parentInterfaceDef"></param> 
    /// <returns></returns> 
    public static bool DoesAnySubTypeImplementInterface(this TypeDefinition childType, TypeDefinition parentInterfaceDef) 
    { 
     Debug.Assert(parentInterfaceDef.IsInterface); 
     return childType 
    .EnumerateBaseClasses() 
    .Any(typeDefinition => typeDefinition.DoesSpecificTypeImplementInterface(parentInterfaceDef)); 
    } 

    /// <summary> 
    /// Does the childType directly inherit from parentInterface. Base 
    /// classes of childType are not tested 
    /// </summary> 
    /// <param name="childTypeDef"></param> 
    /// <param name="parentInterfaceDef"></param> 
    /// <returns></returns> 
    public static bool DoesSpecificTypeImplementInterface(this TypeDefinition childTypeDef, TypeDefinition parentInterfaceDef) 
    { 
     Debug.Assert(parentInterfaceDef.IsInterface); 
     return childTypeDef 
    .Interfaces 
    .Any(ifaceDef => DoesSpecificInterfaceImplementInterface(ifaceDef.Resolve(), parentInterfaceDef)); 
    } 

    /// <summary> 
    /// Does interface iface0 equal or implement interface iface1 
    /// </summary> 
    /// <param name="iface0"></param> 
    /// <param name="iface1"></param> 
    /// <returns></returns> 
    public static bool DoesSpecificInterfaceImplementInterface(TypeDefinition iface0, TypeDefinition iface1) 
    { 
    Debug.Assert(iface1.IsInterface); 
    Debug.Assert(iface0.IsInterface); 
    return iface0.MetadataToken == iface1.MetadataToken || iface0.DoesAnySubTypeImplementInterface(iface1); 
    } 

    /// <summary> 
    /// Is source type assignable to target type 
    /// </summary> 
    /// <param name="target"></param> 
    /// <param name="source"></param> 
    /// <returns></returns> 
    public static bool IsAssignableFrom(this TypeDefinition target, TypeDefinition source) 
    => target == source 
    || target.MetadataToken == source.MetadataToken 
    || source.IsSubclassOf(target) 
    || target.IsInterface && source.DoesAnySubTypeImplementInterface(target); 

    /// <summary> 
    /// Enumerate the current type, it's parent and all the way to the top type 
    /// </summary> 
    /// <param name="klassType"></param> 
    /// <returns></returns> 
    public static IEnumerable<TypeDefinition> EnumerateBaseClasses(this TypeDefinition klassType) 
    { 
     for (var typeDefinition = klassType; typeDefinition != null; typeDefinition = typeDefinition.BaseType?.Resolve()) 
     { 
     yield return typeDefinition; 
     } 
    } 
} 
Verwandte Themen