如何防止 MemberInfo.IsDefined 在不相关的属性上抛出 FileNotFoundException? [英] How to prevent MemberInfo.IsDefined from throwing FileNotFoundException on irrelevant attributes?
问题描述
我的项目引用 TypesDefinitionAssembly
的类型为 SomeType
,它由 XSerializationLibrary
和 的属性
.XSerializationOptions
标记YSerializationLibrary
中的 >YSerializationOptions
My project references TypesDefinitionAssembly
with type SomeType
, which is marked by attributes XSerializationOptions
from XSerializationLibrary
and YSerializationOptions
from YSerializationLibrary
.
显然,要检查SomeType
是否被XSerializationOptions
标记,我还需要引用XSerializationLibrary
.但是,我不想引用 YSerializationLibrary
(甚至可能不可用).
Obviously, to check whether SomeType
is marked by XSerializationOptions
, I need to reference XSerializationLibrary
as well. However, I don't want to reference YSerializationLibrary
(which might even not be available).
目前,调用
typeof(SomeType).IsDefined(typeof(XSerializationOptions))
失败,因为 IsDefined
出于某种原因遍历所有属性并尝试解析它们的所有类型.异常看起来像:
fails because IsDefined
, for some reason, walks through all the attributes and tries to resolve all their types. The exception looks like:
System.IO.FileNotFoundException: Could not load file or assembly 'YSerializationLibrary, Version=1.2.3.4, Culture=neutral, PublicKeyToken=0123456789abcdef' or one of its dependencies. The system cannot find the file specified.
at System.ModuleHandle.ResolveType(RuntimeModule module, Int32 typeToken, IntPtr* typeInstArgs, Int32 typeInstCount, IntPtr* methodInstArgs, Int32 methodInstCount, ObjectHandleOnStack type)
at System.ModuleHandle.ResolveTypeHandleInternal(RuntimeModule module, Int32 typeToken, RuntimeTypeHandle[] typeInstantiationContext, RuntimeTypeHandle[] methodInstantiationContext)
at System.ModuleHandle.ResolveTypeHandle(Int32 typeToken, RuntimeTypeHandle[] typeInstantiationContext, RuntimeTypeHandle[] methodInstantiationContext)
at System.Reflection.RuntimeModule.ResolveType(Int32 metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments)
at System.Reflection.CustomAttribute.FilterCustomAttributeRecord(CustomAttributeRecord caRecord, MetadataImport scope, Assembly& lastAptcaOkAssembly, RuntimeModule decoratedModule, MetadataToken decoratedToken, RuntimeType attributeFilterType, Boolean mustBeInheritable, Object[] attributes, IList derivedAttributes, RuntimeType& attributeType, IRuntimeMethodInfo& ctor, Boolean& ctorHasParameters, Boolean& isVarArg)
at System.Reflection.CustomAttribute.IsCustomAttributeDefined(RuntimeModule decoratedModule, Int32 decoratedMetadataToken, RuntimeType attributeFilterType, Int32 attributeCtorToken, Boolean mustBeInheritable)
at System.Reflection.CustomAttribute.IsDefined(RuntimeType type, RuntimeType caType, Boolean inherit)
有没有办法解决这个问题?如何在不引用完全不相关的 YSerializationLibrary
的情况下检查 XSerializationOptions
是否在 SomeType
上定义?
Is it possible someway to workaround this problem? How do I check whether XSerializationOptions
is defined on SomeType
without referencing a completely irrelevant YSerializationLibrary
?
一旦您考虑到 XSerializationLibrary
本身调用了 Enum.IsDefined
,问题就会变得更糟;因此,除非您还引用了 YSerializationLibrary
,否则不可能使用 SomeType
与 XSerializationLibrary
进行序列化.
The problem becomes even worse once you consider that XSerializationLibrary
itself calls to Enum.IsDefined
; and, as such, it becomes impossible to use SomeType
for serialization with XSerializationLibrary
unless you also reference YSerializationLibrary
.
推荐答案
我不确定你最后想要实现什么,因为在运行时不加载程序集严重限制了你的能力,因为 CLR 类型解析器在类型加载时加载依赖程序集,撇开问题不谈,您可以使用 Mono.Cecil 来检查属性是否定义,而依赖程序集没有被引用甚至不存在.
I'm not sure what you want to achieve at the end, as not loading Assemblies during run-time severely limits what you can do, because CLR Type Resolver loads dependent assemblies on type loads, issues aside, you can use Mono.Cecil to check attributes are defined without dependent assemblies being references or even present.
这里有一个小样本
来自 OptionX 程序集的 MyXAttribute:
public class MyXAttribute:Attribute
{
public string TextX { get; set; }
}
来自 OptionY 程序集的 MyYAttribute:
public class MyYAttribute:Attribute
{
public string TextX { get; set; }
}
来自 TestC 程序集的 MyClass:(同时引用了 OptionX 和 OptionY 程序集)
[MyX(TextX="x")]
[MyY(TextY="y")]
class MyClass
{
}
来自主应用程序的解析器:(没有对 TestC、OptionX 和 OptionY 程序集的任何引用,并且在解析过程中不存在 OptionX 和 OptionY)
static void Main(string[] args)
{
var assemblyPath = @"lib\TestC.exe"; //only Testc.exe here not dependent assemblies
var typeFullname = "TestC.MyClass";
var attributeFullName = "OptionX.MyXAttribute";
var assembly = AssemblyDefinition.ReadAssembly(assemblyPath);
var type=assembly.MainModule.Types.First(t => t.FullName == typeFullname);
var attributes=type.CustomAttributes.Where(a => a.AttributeType.FullName == attributeFullName).ToList();
if (attributes.Count == 0)
{
//type is not decorated with attribute
return;
}
Console.WriteLine("Args");
foreach (var a in attributes)
foreach(var arg in a.ConstructorArguments)
Console.WriteLine("{0}: {1}",arg.Type.Name,arg.Value);
Console.WriteLine("Properties");
foreach(var a in attributes)
foreach(var p in a.Properties)
Console.WriteLine("{0}: {1}",p.Name,p.Argument.Value);
}
这篇关于如何防止 MemberInfo.IsDefined 在不相关的属性上抛出 FileNotFoundException?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!