gpt4 book ai didi

c# - 如何使用 Mono.Cecil 实现 IsAssignableFrom

转载 作者:行者123 更新时间:2023-11-30 16:46:55 25 4
gpt4 key购买 nike

我有一个类型 Type,我希望在程序集中搜索派生类型。

出于性能原因,我正在尝试使用 Mono.Cecil 预扫描程序集。扫描和加载所有程序集花费的时间太长,建议使用 cecil 进行预扫描要快得多,因为只有一小部分可用程序集具有匹配类型。

到目前为止,我有以下仅适用于接口(interface)的内容。

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

我如何扩展它以使其也适用于基类?

最佳答案

主要功能改为

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 代码是下面定义 IsAssignableFrom 的地方

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

关于c# - 如何使用 Mono.Cecil 实现 IsAssignableFrom,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40018991/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com