13

尝试调试 C# 应用程序上的问题时,我偶然发现了这个问题,这是导致应用程序故障的原因。

基本上我有这个代码:

double scale = 1;
double startScale = 1;
...
scale = (e.Scale - 1) * startScale;
if(scale <= 1)
    scale = 1;
...

发生的情况是,即使scale大于 1,执行也会进入 ifscale最终始终为 1 的内部。

这仅在发布版本中发生。

有人知道发生了什么吗?

编辑

这是 Xamarin Forms 的自定义控件的几乎(仅缺少什么都不做的 ctor,取自他们的示例以实现捏合手势(此处)。

public class PinchView : ContentView
{
    private double StartScale = 1;
    private double CurrentScale = 1;
    private double XOffset = 0;
    private double YOffset = 0;

    ...

    private void PinchGesture_PinchUpdated(object sender, PinchGestureUpdatedEventArgs e)
    {
        if (e.Status == GestureStatus.Started)
        {
            // Store the current scale factor applied to the wrapped user interface element,
            // and zero the components for the center point of the translate transform.
            StartScale = Content.Scale;
            Content.AnchorX = 0;
            Content.AnchorY = 0;
        }

        if (e.Status == GestureStatus.Running)
        {
            // Calculate the scale factor to be applied.
            CurrentScale += (e.Scale - 1) * StartScale;
            if(CurrentScale <= 1)
            {
                CurrentScale = 1;
            }

            // The ScaleOrigin is in relative coordinates to the wrapped user interface element,
            // so get the X pixel coordinate.
            double renderedX = Content.X + XOffset;
            double deltaX = renderedX / Width;
            double deltaWidth = Width / (Content.Width * StartScale);
            double originX = (e.ScaleOrigin.X - deltaX) * deltaWidth;

            // The ScaleOrigin is in relative coordinates to the wrapped user interface element,
            // so get the Y pixel coordinate.
            double renderedY = Content.Y + YOffset;
            double deltaY = renderedY / Height;
            double deltaHeight = Height / (Content.Height * StartScale);
            double originY = (e.ScaleOrigin.Y - deltaY) * deltaHeight;

            // Calculate the transformed element pixel coordinates.
            double targetX = XOffset - (originX * Content.Width) * (CurrentScale - StartScale);
            double targetY = YOffset - (originY * Content.Height) * (CurrentScale - StartScale);

            // Apply translation based on the change in origin.
            Content.TranslationX = targetX.Clamp(-Content.Width * (CurrentScale - 1), 0);
            Content.TranslationY = targetY.Clamp(-Content.Height * (CurrentScale - 1), 0);

            // Apply scale factor.
            Content.Scale = CurrentScale;
        }

        if (e.Status == GestureStatus.Completed)
        {
            // Store the translation delta's of the wrapped user interface element.
            XOffset = Content.TranslationX;
            YOffset = Content.TranslationY;
        }
    }
}

这些是我的调试会话的步骤(e.Scale已优化且不可见,但您可以看到CurrentScale更改的值):

在此处输入图像描述

在此处输入图像描述

在此处输入图像描述

在此处输入图像描述

在此处输入图像描述

4

1 回答 1

1

CurrentScale并且StartScale是实例字段而不是方法字段,因此它们可能会受到另一个线程的影响。要检测任何竞争条件,您可以锁定该块并再次调试:

lock (StartScale) {
    // Calculate the scale factor to be applied.
    CurrentScale += (e.Scale - 1) * StartScale;
    if(CurrentScale <= 1)
    {
        CurrentScale = 1;
    }
}

如果这可行,您应该使用局部变量获得更好的结果以减少外部干扰(并因此删除锁定):

lock (StartScale) {
    // Calculate the scale factor to be applied.
    var localCurrentScale = CurrentScale + (e.Scale - 1) * StartScale;
    if(localCurrentScale <= 1)
    {
        CurrentScale = 1;
    } else CurrentScale = localCurrentScale;
}

您可以使用 Redgate Reflector 或 Telerik JustDecompile(免费)之类的工具来分析您编译的程序集(它非常易读)并查看在编译期间优化了哪些内容。

注意:StartScale 是一个坏锁,但对于此调试很好。

于 2017-12-20T07:49:34.670 回答