我的项目引用的类型为 SomeType
的TypesDefinitionAssembly
,该类型由来自XSerializationLibrary
的属性XSerializationOptions
和来自YSerializationLibrary
的属性YSerializationOptions
标记。
显然,要检查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)
是否有可能解决此问题?如何在不引用完全不相关的YSerializationLibrary
的情况下检查XSerializationOptions
是否在SomeType
上定义?
一旦你考虑到XSerializationLibrary
本身调用Enum.IsDefined
,问题就会变得更糟;因此,除非你也引用YSerializationLibrary
,否则不可能使用SomeType
进行XSerializationLibrary
的序列化。
在运行时无法访问 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
我不确定您最后要实现什么,因为在运行时不加载程序集会严重限制您可以执行的操作,因为 CLR 类型解析程序在类型加载时加载依赖程序集,除了问题之外,您可以使用 Mono.Cecil 检查属性是否定义,而无需引用依赖程序集,甚至不存在。
这是一个小示例
MyXAttribute from OptionX Assembly:
public class MyXAttribute:Attribute
{
public string TextX { get; set; }
}
MyYA来自OptionY大会:
public class MyYAttribute:Attribute
{
public string TextX { get; set; }
}
来自 TestC 汇编的 MyClass:(同时引用选项 X 和选项 Y 程序集(
[MyX(TextX="x")]
[MyY(TextY="y")]
class MyClass
{
}
来自主应用程序的解析器:(没有任何对 TestC、OptionX 和 OptionY 程序集的引用,并且在解析过程中不存在 OptionX 和 OptionY(
static void Main(string[] args)
{
var assemblyPath = @"libTestC.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);
}