如何防止 MemberInfo.IsDefined 在不相关的属性上抛出 FileNotFoundException? [英] How to prevent MemberInfo.IsDefined from throwing FileNotFoundException on irrelevant attributes?

查看:28
本文介绍了如何防止 MemberInfo.IsDefined 在不相关的属性上抛出 FileNotFoundException?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的项目引用 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,否则不可能使用 SomeTypeXSerializationLibrary 进行序列化.

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆