2016-10-13 2 views
1

유형 유형 파생 형식의 어셈블리를 검색하고 싶습니다.Mono.Cecil을 사용하여 IsAssignableFrom을 구현하는 방법

Mono.Cecil을 사용하여 성능상의 이유로 어셈블리를 사전 검사하려고합니다. 모든 어셈블리 스캔 및 로딩 작업이 너무 오래 걸리며 사용 가능한 어셈블리의 일부분 만 일치하는 유형으로 사전 검사를 수행하는 것이 훨씬 쉽습니다.

지금까지 인터페이스에 대해서만 작동하는 아래 항목이 있습니다.

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; 
    } 

기본 클래스에서도이 기능을 확장 할 수 있습니까?

+0

이하 수업? – Igor

+0

인터페이스가 아닙니다. – bradgonesurfing

+0

"일반 클래스"라는 단어를 "기본 클래스" – bradgonesurfing

답변

1

주요 기능은

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[] { }; 
    } 

} 

로 변경하고 지원 Mono.Cecil 코드 일지 어떨지는 정의된다 당신이 참조 할 때 normal``무엇을 의미합니까

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; 
     } 
    } 
}