当程序集用作子类时,CurrentDomain.AssemblyResolve 不会触发
我正在尝试使用 CurrentDomain.AssemblyResolve
事件来加载标记为嵌入式资源的 DLL。具体来说,我的问题来自于我试图将程序集用作子类,如下所示:
#define BROKEN
using System;
using System.Reflection;
using TestCompanyInc;
namespace TestConsole
{
#if BROKEN
// This is how I NEED to use it
class Program : SubClass
#else
// This is only here as a test to make sure I wired
// CurrentDomain.AssemblyResolve correctly
class Program
#endif
{
static int Main(string[] args)
{
AppDomain.CurrentDomain.AssemblyResolve += (sender, eventArgs) =>
{
string resourceName = Assembly.GetExecutingAssembly()
.GetName().Name
+ "." + new AssemblyName(eventArgs.Name).Name + ".dll";
Console.WriteLine("About to lookup {0}", resourceName);
using (var stream = Assembly.GetExecutingAssembly()
.GetManifestResourceStream(resourceName))
{
byte[] assemblyData = new byte[stream.Length];
stream.Read(assemblyData, 0, assemblyData.Length);
return Assembly.Load(assemblyData);
}
};
Program p = new Program(args);
return p.Run();
}
public Program(string[] args)
{
}
public int Run()
{
#if BROKEN
// This is how I NEED to use it
Console.WriteLine(TestProperty);
#else
// This is only here as a test to make sure I wired
// CurrentDomain.AssemblyResolve correctly
SubClass sc = new SubClass();
Console.WriteLine(sc.TestProperty);
#endif
Console.ReadKey();
return 0;
}
}
}
测试类 SubClass
定义为:
namespace TestCompanyInc
{
public class SubClass
{
public SubClass()
{
TestProperty = "Init'd";
}
public string TestProperty { get; set; }
}
}
如果第一行 #define BROKEN< /code> 未注释,则
CurrentDomain.AssemblyResolve
事件将永远不会触发,并且会引发 System.IO.FileNotFoundException,并且我被告知无法找到 SubClass
。如果第一行被删除或注释掉,那么它将触发该事件(但我不能以这种方式使用它)。
我还尝试将 Main
移动到其自己的类中,而不是让同一个类创建其自身的实例,但我得到了完全相同异常。
那么,如何正确连接此事件,以便在这些条件下加载此程序集?
在 VS 2010 .NET 4 中编译,如果这对任何人都有影响的话。另外,对于任何尝试重新创建此内容的人。子类在它自己的项目中。添加子类作为 TestConsole 的引用并将其标记为 Copy Local = False。我在某处读到,这不能是项目引用,而是对 DLL 的直接引用。然后,将 DLL 文件 添加到 TestConsole 项目并将其标记为嵌入式资源,而不是默认的内容。
I am trying to use the CurrentDomain.AssemblyResolve
event to load a DLL that is marked as an Embedded Resource. My problem, specifically, comes from the fact that I am trying to use the assembly as a subclass, like so:
#define BROKEN
using System;
using System.Reflection;
using TestCompanyInc;
namespace TestConsole
{
#if BROKEN
// This is how I NEED to use it
class Program : SubClass
#else
// This is only here as a test to make sure I wired
// CurrentDomain.AssemblyResolve correctly
class Program
#endif
{
static int Main(string[] args)
{
AppDomain.CurrentDomain.AssemblyResolve += (sender, eventArgs) =>
{
string resourceName = Assembly.GetExecutingAssembly()
.GetName().Name
+ "." + new AssemblyName(eventArgs.Name).Name + ".dll";
Console.WriteLine("About to lookup {0}", resourceName);
using (var stream = Assembly.GetExecutingAssembly()
.GetManifestResourceStream(resourceName))
{
byte[] assemblyData = new byte[stream.Length];
stream.Read(assemblyData, 0, assemblyData.Length);
return Assembly.Load(assemblyData);
}
};
Program p = new Program(args);
return p.Run();
}
public Program(string[] args)
{
}
public int Run()
{
#if BROKEN
// This is how I NEED to use it
Console.WriteLine(TestProperty);
#else
// This is only here as a test to make sure I wired
// CurrentDomain.AssemblyResolve correctly
SubClass sc = new SubClass();
Console.WriteLine(sc.TestProperty);
#endif
Console.ReadKey();
return 0;
}
}
}
The test class SubClass
is defined as:
namespace TestCompanyInc
{
public class SubClass
{
public SubClass()
{
TestProperty = "Init'd";
}
public string TestProperty { get; set; }
}
}
If the first line #define BROKEN
is left uncommented, then the CurrentDomain.AssemblyResolve
event will never fire and System.IO.FileNotFoundException is thrown and I am told that SubClass
can not be found. If the first line is removed or commented out, then it will fire the event (but I can't use it this way).
I have also tried moving Main
into its own class instead of having the same class create an instance of itself, but I get the exact same exception.
So, how do I get this event wired up correctly so it will load this assembly under these conditions?
Compiled in VS 2010 .NET 4, if that makes a difference to anyone. Also, for anyone trying to recreate this. SubClass is in its own project. Add SubClass as a Reference to TestConsole and mark it as Copy Local = False. I have read, somewhere, that this can not be a Project Reference, but a direct reference to the DLL. Then, add the DLL file to the TestConsole project and mark it as an Embedded Resource, not the default of Content.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
考虑加载顺序...为了 JIT 并调用 Main,它必须了解 Program。如果不加载基类,它就无法理解 Program,这需要特殊处理。该事件不会触发因为它尚未注册(因为 Main 尚未启动)。
那是行不通的。做到这一点的唯一方法是拥有一个不依赖于其他任何东西的入口点。请注意,JIT 是在方法启动之前完成的,因此 Main 也不能涉及任何未知的内容。例如,您可能会这样做:
请注意,我们需要上面的 2 个方法,因为它无法 JIT Main,除非它可以完全解析 Program。通过上述内容,事件应该在调用 MainCore() 之前触发(即在 MainCore 的 JIT 期间)。
Think about load-order... In order to JIT and invoke Main, it must understand Program. It can't understand Program without loading the base-class, which needs special handling. The event doesn't fire because it hasn't registered yet (because Main hasn't started).
That cannot work. The only way you can do this is to have an entry-point that doesn't depend on anything else. Note that JIT is done before the method starts, so the Main also can't involve anything that isn't known. For example, you might do:
Note we need 2 methods above since it can't JIT Main unless it can fully resolve Program. With the above, the event should fire just before MainCore() is invoked (I.e. During JIT for MainCore).