如何防止MemberInfo.IsDefined对不相关的属性抛出FileNotFoundException?

时间:2014-09-12 08:31:30

标签: c# .net reflection system.reflection

我的项目引用TypesDefinitionAssembly类型SomeType,其中XSerializationOptions的{​​{1}}和XSerializationLibrary的{​​{1}}标记。

显然,要检查YSerializationOptions是否标有YSerializationLibrary,我还需要引用SomeType。但是,我不想引用XSerializationOptions(甚至可能无法使用)。

目前,致电

XSerializationLibrary

失败,因为YSerializationLibrary由于某种原因,遍历所有属性并尝试解析所有类型。例外情况如下:

typeof(SomeType).IsDefined(typeof(XSerializationOptions))

是否有可能解决此问题?如何检查IsDefined是否定义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) 而未引用完全无关的XSerializationOptions

一旦您认为SomeType本身要求YSerializationLibrary,问题就会变得更糟;因此,除非您同时引用XSerializationLibrary,否则无法使用Enum.IsDefinedSomeType进行序列化。

2 个答案:

答案 0 :(得分:1)

在您运行时无法访问Y库的特殊情况下,您可能会尝试使用与您无权访问的名称和名称空间相同的新类伪造该属性:

using System;
using System.Linq;
using ClassLibraryAssembly;
using OtherAssemblyX;

// This is a faking attribute, with same signature of that in unavailable assembly.
namespace OtherAssemblyY
{
    public class YAttribute : Attribute
    {
    }
}

namespace MainAssembly
{
    class Program
    {
        static void Main(string[] args)
        {
            var type = typeof (SomeType);

            AppDomain.CurrentDomain.AssemblyResolve += (sender, eventArgs) =>
            {
                if (eventArgs.Name == "OtherAssemblyY, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null")
                    return typeof(Program).Assembly;
                return null;
            };

            Console.WriteLine(type.IsDefined(typeof (XAttribute), true));

            foreach (var attrObject in type.GetCustomAttributes(true))
            {
                Console.WriteLine("Attribute found: {0}, Assembly: {1}", attrObject, attrObject.GetType().Assembly);
            }
        }
    }
}

结果:

True
Attribute found: OtherAssemblyY.YAttribute, Assembly: MainAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
Attribute found: OtherAssemblyX.XAttribute, Assembly: OtherAssemblyX, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null

答案 1 :(得分:1)

我不确定你最终想要实现什么,因为在运行期间不加载程序集严重限制了你可以做的事情,因为CLR Type Resolver在类型加载时加载依赖程序集,除了问题,你可以使用Mono.Cecil来检查属性是在没有依赖程序集引用甚至存在的情况下定义的。

这是一个小样本

来自OptionX Assembly的

MyXAttribute:

 public class MyXAttribute:Attribute
    {
        public string TextX { get; set; }
    }
来自OptionY汇编的

MyYAttribute:

 public class MyYAttribute:Attribute
    {
        public string TextX { get; set; }
    }

来自TestC Assembly的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);

    }