从程序集文件中获取自定义属性数据并在之后解锁

Get custom attribute data from assembly file and unlock it afterwise

程序集 A 声明了一个应用于程序集 B 的自定义程序集属性。

class MyAssemblyAttribute : Attribute { /* ... */ }

我需要从程序集 A 的方法中获取程序集 B 的属性数据,而不保持程序集 B 的加载。

程序集 A 中的伪代码:

var domain = AppDomain.Create();
MyAssemblyAttribute attr = null;
string path = "B.dll";
domain.DoCallback(() => {
       attr = Assembly.Load(path)
          .GetCustomAttributes()
          .OfType<MyAssemblyAttribute>()
          .First();
      });

AppDomain.Unload(domain);
File.Delete(path);
File.WriteAllBytes(path, ...);
return expectedAttr.Equals(attr);

我该怎么做?

我可以重新编译这两个程序集。我不能使用 Mono.Cecil 或 IKVM 等第 3 方的东西。

我终于完成了这项工作:

var domain = AppDomain.CreateDomain(
    "CompiledAssemblyCheck",
    null,
    new AppDomainSetup()
    {
        LoaderOptimization = LoaderOptimization.MultiDomainHost,
        PrivateBinPath = Path.GetDirectoryName(Path.GetFullPath(otherAssembly)),
        ShadowCopyFiles = "true"
    });
try
{

    var data = File.ReadAllBytes(otherAssembly);

    string myPath = new Uri(executingAssembly.GetName().CodeBase).LocalPath;
    var proxy = (AssemblyAnyLoadProxy)domain.CreateInstanceFromAndUnwrap(myPath, typeof(AssemblyAnyLoadProxy).FullName);

    proxy.LoadFrom(myPath);

    int outputAssemblyId = proxy.Load(data);

    bool same = proxy.CompareAttribute(outputAssemblyId, typeof(MyAssemblyAttribute).FullName, expectedArgs);
}
finally
{
    AppDomain.Unload(domain);
}



    [Serializable]
    class AssemblyAnyLoadProxy : MarshalByRefObject
    {
        List<Assembly> _assemblies=new List<Assembly>();

        public int Load(byte[] raw)
        {
            Assembly asm = Assembly.ReflectionOnlyLoad(raw);
            return Add(asm);
        }

        public int LoadFrom(string assemblyFile)
        {
            Assembly asm = Assembly.ReflectionOnlyLoadFrom(assemblyFile);
            return Add(asm);
        }

        int Add(Assembly asm)
        {

            _assemblies.Add(asm);
            return _assemblies.Count - 1;
        }

        public bool CompareAttribute(int assembly, string fullName, object[] args)
        {
            var attrs = CustomAttributeData.GetCustomAttributes(_assemblies[assembly]);
            CustomAttributeData attr = attrs.FirstOrDefault(x => x.Constructor.DeclaringType.FullName == fullName);
            return attr?.ConstructorArguments.Select(x => x.Value).SequenceEqual(args) ?? false;
        }
    }