Lon*_*kli 6 c# garbage-collection
(标题是:"TypeLoadException并不总是包含在使用了Reflection的TargetInvocationException中")
使用BLToolkit我发现了一个有趣的事实 - methodInfo.Invoke并不总是在调用方法中捕获异常.
参见示例 - 它在方法的静态构造函数中模拟异常,通过反射调用.
问题是TestComponent继承自Component AND并重写了Dispose方法.所以在这个示例中将有2条消息 - 一个"句柄"和一个"unhandle" - 似乎组件在较低级别的Reflection内部具有不同的处理.
如果我们注释掉方法Dispose(bool disposing) - 我们只会收到"handle"消息.
任何人都可以解释为什么会发生并提出解决方案?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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
这与反思无关; 你只得到一个非常相似的结果:
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");
Run Code Online (Sandbox Code Playgroud)
它实际上写得"快乐"; 未处理的异常似乎来自GC,可能是因为它试图收集一个部分构造的对象(它从不调用实例构造函数),然后它就会崩溃...特别注意它们在不同的线程上(我'我很确定未处理的是在GC线程上).作为GC /线程,它可能是一种痛苦的重现; 我GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);在本地添加,只是为了强制GC发生,所以我经常看到它.迷人.
由于实例构造函数(TestComponent())和终结器(~TestComponent())都没有被调用,所以你没有办法(我可以告诉)修复它.
遗憾的是,我可以在这里建议的主要是:没有类型初始化器失败:(
我可以做的一件事就是欺骗运行时:
object obj = FormatterServices.GetUninitializedObject(typeof(TestComponent));
Run Code Online (Sandbox Code Playgroud)
这仍然会遇到类型初始化程序并失败,但该对象似乎并没有丢失.也许这条路线没有标记为最终确定.因此GC并不那么讨厌它.
如果类型初始化程序是borked,你仍然会遇到使用此对象的主要问题.
所以在你的代码中,你可能有:
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();
}
}
}
Run Code Online (Sandbox Code Playgroud)
现在:
| 归档时间: |
|
| 查看次数: |
1496 次 |
| 最近记录: |