2015-07-28 82 views
3

我正在为Windows Phone 8.1(Silverlight)开发C#应用程序。最近我遇到了与应用程序入睡和故事板有关的问题。Catch不执行其代码

构造变为如下:

class X : DependencyObject 
{ 
    public static readonly DependencyProperty vProperty = 
     DependencyProperty.Register("v", typeof(double), typeof(X), new PropertyMetadata(0.0)); 

    public double v 
    { 
     get 
     { 
      return (double)GetValue(vProperty); 
     } 
     set 
     { 
      SetValue(vProperty, value); 
     } 
    } 

    private Storyboard _storyboard; 
    void Prepare() 
    { 
     _storyboard = new Storyboard(); 
     var animation= new DoubleAnimation 
     { 
      From = 0, 
      To = 1, 
      BeginTime = 0, 
      Duration = 0, 
     }; 
     _storyboard.Children.Add(animation); 
     Storyboard.SetTarget(animation, this); 
     Storyboard.SetTargetProperty(animation, vProperty); 
    } 

    void Go() 
    { 
     _storyboard.Begin(); 
    } 
} 

有从_storyboard.Begin()的内部抛出一个NullReferenceException如果应用设备被置于背景“准备”和“去”(约10%的再现速率之间)。当然,它最终会崩溃。

我无法确定问题的来源,因为我需要quickfix,因此我决定在这种罕见的情况下发现这个NullRefereneceException。这是真正的问题开始的地方。我已经改变了“去”实施:

public void Go() 
    { 
     Debug.WriteLine("BreakPoint 1"); 
     try 
     { 
      _storyboard.Begin(); 
     } 
     catch (NullReferenceException) 
     { 
      Debug.WriteLine("BreakPoint 2"); 
     } 
    } 

之后崩溃是不可复制的所有,但问题是,“断点2”从不打(在输出中没有打印其一)。 “BreakPoint 1”通常也会被打印和打印。将NullReferenceException更改为其他异常类型(不是父类型的c)会导致崩溃重新出现。

那么......这里发生了什么事?这崩溃缓存或不?这是什么奇怪的行为?假设它能按预期工作是否安全?

附加问题:也许你知道为什么原始代码崩溃的第一个地方?

编辑: 结束TargetInvocationExceptions的internalException的堆栈跟踪看起来如下:

at MS.Internal.XcpImports.CheckHResult(UInt32 hr) 
    at MS.Internal.XcpImports.Storyboard_Begin(Storyboard storyboard) 
    at System.Windows.Media.Animation.Storyboard.Begin() 
    at X.Go() 
+1

那么程序仍然崩溃或没有?如果你有它捕获一个通用的'例外'会发生什么? – user1666620

+0

它没有崩溃,但它看起来像捕获内的代码不会执行。任何NullRefrenceException父类的异常类型都会修复崩溃。任何其他异常类型都不能修复崩溃。 – Yester

+3

如果你得到一个'TargetInvocationException',那么这就是你需要捕获的。 'InnerException'属性可能是你的'NullReferenceException',但你不能理解(除非你使用C#6.0,你可以这样做:'catch(TargetInvocationException ex)when(ex.InnerException是NullReferenceException)') 。 –

回答

4

我知道你说你已经尝试使用父类型的NullReferenceException,但请尝试以下没有运行在调试器:

public void Go() 
{ 
    Debug.WriteLine("BreakPoint 1"); 
    try 
    { 
     _storyboard.Begin(); 
    } 
    catch (Exception) 
    { 
     Debug.WriteLine("BreakPoint 2"); 
     System.Diagnostics.Debugger.Break(); 
    } 
} 

我怀疑是美中不足的是不触发,因为你是在调试器中运行。如果.Break();不起作用,请尝试System.Diagnostics.Debugger.Launch();。如果.Launch();不起作用,最后还要在catch中尝试throw;

如果调试器试图在任何一种情况下启动,那么你有另一个线索。

UPDATE

我不能给你全部的原因,这可能发生,因为它可能无法准确确定是什么原因造成它在你的情况。

由于使用多线程,我见过这样的行为。使用不带附加的调试器运行时,多线程的行为可能会有所不同。定时问题和竞态条件可以防止在调试器中抛出异常,否则可能在没有附加调试器的情况下频繁发生异常。

我也遇到过在第三方代码中使用System.Diagnostics.Debugger.IsAttached的情况,甚至导致应用程序使用此检查的if语句的行为有所不同。

最后,我有时无法想出行为发生的具体原因。我已经学会了使用System.Diagnostics.Debugger.Break()方法,只要我看到行为的展现方式取决于调试器是否连接。有时它真的只是一个直觉

+0

你是对的,即使调试器没有在那里的断点处停止,该catch中的代码也会被执行。 Debugger.Break()使应用程序结束而不会打破调试器会话。我也尝试从catch块中改变一些图形元素,并且它工作得很好。你能解释这种行为吗? – Yester

+0

@Yester我已经用一些附加信息更新了答案。不幸的是,如果没有您的精确设置和视频工作室解决方案的副本,我无法给您一个确切的答案,说明为什么这种行为在您的情况下显现。我已经提供了一些在更新后的答案中查找的内容。不幸的是,您可能需要*接受*,否则您可能无法确定为什么会发生这种情况。但请保持这种情况发生在你的脑海里,以便在另一种情况下再次发生时可以尝试识别它。这就是我所做的。 –

+0

感谢您的帮助。这并不能解释为什么会发生这种情况,但现在我可以得到最好的结果:-) – Yester