(标题是:“TypeLoadException并不总是包含在使用了Reflection的TargetInvocationException中”)
使用BLToolkit我发现了一个有趣的事实 - methodInfo.Invoke并不总是在调用方法中捕获异常。
参见示例 - 它在方法的静态构造函数中模拟异常,通过反射调用。
问题是TestComponent继承自Component AND并重写了Dispose方法。 所以在这个示例中将有2条消息 - 一个“句柄”和一个“unhandle” - 看起来组件在较低级别的Reflection内部有不同的处理。
如果我们注释掉方法 Dispose(bool disposing) - 我们只会收到“句柄”消息。
任何人都可以解释为什么会发生并提出解决方案吗? BLToolkit中的try-catch无法标记为答案 - 我不是他们团队的成员:)
class Program
{
static void Main()
{
AppDomain.CurrentDomain.UnhandledException +=
(sender, eventArgs) => Console.WriteLine("unHandled " + eventArgs.ExceptionObject.GetType().FullName);
try
{
try
{
var instance = Activator.CreateInstance(typeof(ComponentExecutor));
MethodInfo mi = typeof(ComponentExecutor).GetMethod("Do");
BindingFlags bf = BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly |
BindingFlags.InvokeMethod;
mi.Invoke(instance, bf, null, new object[0], CultureInfo.InvariantCulture);
}
catch (TargetInvocationException tarEx)
{
throw tarEx.InnerException;
}
}
catch (Exception ex)
{
Console.WriteLine("Handled " + ex.GetType().FullName);
}
}
class ComponentExecutor
{
public void Do()
{
new TestComponent().Do();
}
}
class TestComponent : Component
{
static TestComponent()
{
throw new NullReferenceException();
}
[MethodImpl(MethodImplOptions.NoInlining)]
public void Do()
{
Console.WriteLine("Doing");
}
protected override void Dispose(bool disposing)
{
Console.WriteLine("Disposing");
base.Dispose(disposing);
}
}
}
答案 0 :(得分:8)
这与反思无关;你只得到了一个非常相似的结果:
AppDomain.CurrentDomain.UnhandledException +=
(sender, eventArgs) => Console.WriteLine("unHandled " + eventArgs.ExceptionObject.GetType().FullName);
try
{
new TestComponent();
}
catch (Exception ex)
{
Console.WriteLine("Handled " + ex.GetType().FullName);
}
Console.WriteLine("happy");
它实际上写的是“快乐”;未处理的异常似乎来自GC,可能是因为它试图收集一个部分构造的对象(它从不调用实例构造函数),然后它就会崩溃...特别注意它们在不同的线程上(我很确定未处理的是在GC线程上)。作为GC /线程,它可能是一种痛苦的重现;我在本地添加了GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
,只是为了强制GC发生,所以我经常看到它。迷人。
由于实例构造函数(TestComponent()
)和终结器(~TestComponent()
)都没有被调用,你有没有办法(我可以告诉)解决这个问题。< / p>
遗憾的是,我可以在这里建议的主要问题是:没有类型初始化器失败:(
我可以工作的一件事就是欺骗运行时:
object obj = FormatterServices.GetUninitializedObject(typeof(TestComponent));
这仍然会遇到类型初始化程序并失败,但该对象似乎并没有丢失。也许这条路线没有标记为最终确定。因此GC不会那么讨厌它。
如果类型初始值设定项被禁止,您仍然会遇到使用此对象的主要问题。
因此,在您的代码中,您可能有:
class ComponentExecutor
{
public void Do()
{
using (var tc = (TestComponent)
FormatterServices.GetUninitializedObject(typeof(TestComponent)))
{
// call the ctor manually
typeof(TestComponent).GetConstructor(Type.EmptyTypes).Invoke(tc, null);
// maybe we can skip this since we are `using`
GC.ReRegisterForFinalize(tc);
tc.Do();
}
}
}
现在: