【问题标题】:Visual Studio C# and Short-circuit evaluationVisual Studio C# 和短路评估
【发布时间】:2017-06-20 09:39:05
【问题描述】:

随着 ||微软操作员在这里描述短路评估Short Circuit Evaluation

但是,我有以下似乎与此过程相矛盾的代码:

  if ((_opcLoaded || DoLoadOPC()) &&
     (_tagsAdded || DoAddTags()) &&
     DoWriteRecipe() && 
     (DoResume()))

我要防止的是,如果 _tagsAdded 为真(DoAddTags 将 _tagsAdded 设置为真),则调用函数 DoAddTags。

但是,我发现即使_tagsAdded 为真,也会调用DoAddTags。 _opcLoadedDoLoadOPC 也是如此。我必须在DoAddTags 中添加一个条件来检查_tagsAdded,这应该没有必要。

有人可以解释为什么会这样吗?

这是完整的代码

    //
                        // Resume a Paused recipe
                    case MonitoredTasks.Resume:
                        Task.Factory.StartNew(() =>
                            {
                                MonitoredTask = MonitoredTasks.None;
                                if ((_opcLoaded || DoLoadOPC()) &&
                                      **(_tagsAdded || DoAddTags())** &&
                                      DoWriteRecipe() && 
                                      (DoResume()))
                                {
                                    MonitoredTask = MonitoredTasks.None;
                                    RunningState = RecipeRunningStates.Running;
                                    Status = CIPStatuses.Running;
                                }
                                else
                                {
                                    MonitoredTask = MonitoredTasks.Resume;
                                }
                            });

                        break;

以及 DoAddTags 的代码

        /// <summary>
    /// Adds all necessary tags to the OPC Server Manager
    /// </summary>
    /// <returns></returns>
    bool DoAddTags()
    {

        bool result = false;
        var oldActivity = Activity;
        //
        // Not doing anything OPC related?
        if (Activity != CIPActivities.AddingOPCTags && !_tagsAdded && Activity != CIPActivities.StartingOPC)
        {
            lock (_locks[LOCK_OPC])
            { 
                Activity = CIPActivities.AddingOPCTags;
                Status = CIPStatuses.Initialising;
                RecipeError = Errors.None;
                try
                {
                    //
                    // Reset connection and internal tags list
                    _serverManager.Reset();

                    //
                    // Now to add all OPC Tags - Area
                    CIPStatusTag = _serverManager.AddTag(_area.CIPStatusTag);
                    RecipeIDTag = _serverManager.AddTag(_area.RecipeIDTag);
                    RecipeInstructionIDTag = _serverManager.AddTag(_area.RecipeInstructionIDTag);
                    HandshakingTag = _serverManager.AddTag(_area.HandshakingTag);
                    GlobalInstructionIDTag = _serverManager.AddTag(_area.GlobalInstructionIDTag);
                    InstructionAttemptsTag = _serverManager.AddTag(_area.InstructionAttemptsTag);

                    //
                    // Area tags OK?
                    if (CIPStatusTag == null || RecipeIDTag == null || RecipeInstructionIDTag == null || HandshakingTag == null || GlobalInstructionIDTag == null || InstructionAttemptsTag == null)
                    {
                        RecipeError = Errors.InvalidAreaTags;
                        DoError(new RecipeErrorHandlerEventArgs(this) { Message = FormatMessage("CIPRecipe.DoAddTags - Invalid AREA Tags"), Sender = this });
                    }
                    else
                    {

                        VM_CIPInstruction vm = null;
                        bool instructionTagErrors = false;
                        //
                        // For each area instruction that is used, assig a link to the instruction
                        foreach (var i in _areaInstructions)
                        {
                            //
                            // Create a View Model for the specified area instruction : this allows us to determine the number of parameters (tags) that apply to the instruction
                            vm = new VM_CIPInstruction(i.Value.Instruction);
                            //
                            // Assign device reference tags
                            if (vm.DeviceReferencesAvailable)
                            {
                                i.Value.DeviceTag = _serverManager.AddTag(i.Value.Instruction.DeviceReferenceTag);
                                instructionTagErrors = i.Value.DeviceTag == null;
                            }
                            //
                            // For  each required parameter, add tag
                            for (int paramNo = 1; paramNo <= vm.NoOfParams; paramNo++)
                            {
                                switch (paramNo)
                                {
                                    case 1:
                                        //
                                        // Tag defined? Add it 
                                        if (vm.AreaInstruction.Param1Tag >= 0)
                                        {
                                            i.Value.Param1 = _serverManager.AddTag(i.Value.Instruction.Param1Tag);

                                            if (i.Value.Param1 == null)
                                            {
                                                instructionTagErrors = true;
                                            }
                                        }
                                        else
                                        {
                                            instructionTagErrors = true;
                                        }
                                        break;
                                    case 2:
                                        //
                                        // Tag defined? Add it 
                                        if (vm.AreaInstruction.Param2Tag >= 0)
                                        {
                                            i.Value.Param2 = _serverManager.AddTag(i.Value.Instruction.Param2Tag);

                                            if (i.Value.Param2 == null)
                                            {
                                                instructionTagErrors = true;
                                            }
                                        }
                                        else
                                        {
                                            instructionTagErrors = true;
                                        }
                                        break;
                                    case 3:
                                        //
                                        // Tag defined? Add it 
                                        if (vm.AreaInstruction.Param3Tag >= 0)
                                        {
                                            i.Value.Param3 = _serverManager.AddTag(i.Value.Instruction.Param3Tag);

                                            if (i.Value.Param3 == null)
                                            {
                                                instructionTagErrors = true;
                                            }
                                        }
                                        else
                                        {
                                            instructionTagErrors = true;
                                        }
                                        break;
                                    case 4:
                                        //
                                        // Tag defined? Add it and then check quality
                                        if (vm.AreaInstruction.Param4Tag >= 0)
                                        {
                                            i.Value.Param4 = _serverManager.AddTag(i.Value.Instruction.Param4Tag);

                                            if (i.Value.Param4 == null)
                                            {
                                                instructionTagErrors = true;
                                            }
                                        }
                                        else
                                        {
                                            instructionTagErrors = true;
                                        }
                                        break;

                                    case 5:
                                        //
                                        // Tag defined? Add it and then check quality
                                        if (vm.AreaInstruction.Param5Tag >= 0)
                                        {
                                            i.Value.Param5 = _serverManager.AddTag(i.Value.Instruction.Param5Tag);

                                            if (i.Value.Param5 == null)
                                            {
                                                instructionTagErrors = true;
                                            }
                                        }
                                        else
                                        {
                                            instructionTagErrors = true;
                                        }
                                        break;

                                    case 6:
                                        //
                                        // Tag defined? Add it and then check quality
                                        if (vm.AreaInstruction.Param6Tag >= 0)
                                        {
                                            i.Value.Param6 = _serverManager.AddTag(i.Value.Instruction.Param6Tag);

                                            if (i.Value.Param6 == null)
                                            {
                                                instructionTagErrors = true;
                                            }
                                        }
                                        else
                                        {
                                            instructionTagErrors = true;
                                        }
                                        break;
                                }
                            }

                            if (instructionTagErrors)
                            {
                                RecipeError = Errors.InvalidInstructionTags;
                                DoError(new RecipeErrorHandlerEventArgs(this) { Message = FormatMessage(String.Format("CIPRecipe.DoAddTags - Invalid Instruction {0} Tags", vm.Name)), Sender = this });
                                break;
                            }
                        }
                        //
                        // Any problems adding tags?
                        if (RecipeError == Errors.None)
                        {
                            Activity = CIPActivities.StartingOPC;
                            //
                            // Once all tags added, start OPC Server
                            result = _serverManager.Start();

                            if (!result)
                            {
                                Status = CIPStatuses.AddTagsFailed;
                                RecipeError = Errors.OPC;
                                DoError(new RecipeErrorHandlerEventArgs(this) { Message = FormatMessage("CIPRecipe.DoAddTags - Start of OPC failed"), Sender = this });
                            }
                            else
                            {
                                **_tagsAdded = true;**
                                Status = CIPStatuses.TagsAdded;
                            }
                        }
                        else
                        {
                            Status = CIPStatuses.AddTagsFailed;
                        }
                    }
                }
                catch (Exception ex)
                {
                    RecipeError = Errors.Exception_AddTags;
                    DoError(new RecipeErrorHandlerEventArgs(this) { Message = FormatMessage("CIPRecipe.DoAddTags"), Exception = ex, Sender = this });
                }
                finally
                {
                    Activity = oldActivity;
                }
            }
        }
        return Status == CIPStatuses.TagsAdded;
    }

我已用 ** 突出显示相关行

在第一次执行时,DoAddTags 被执行并且 _tagsAdded 设置为 TRUE——我在这里放置了一个断点,所以我知道它正在被设置。不久之后(有或没有前一个断点)DoAddTags 再次输入(在第一行)尽管_doAddTags == true。

我什至在代码“(_tagsAdded || DoAddTags())”上设置了一个断点。 _tagsAdded == true,但仍输入 DoAddTags。

所以我看到的是,所有的 Watches/Debugging 信息都与 DoAddTags 一致,而 _tagsAdded == true

【问题讨论】:

  • 很难解开这个表达式可能的副作用。只是不要编写不可读的代码,这需要更多的 if 语句。
  • 无法重现您问题中指定的行为。你确定这些字段之前没有设置为false吗?
  • 您确定调用了 DoAddTags 吗?也许它是从其他地方调用的。我已经检查了 Debug 并且如果 _tagsAdded 为真,则不会调用 DoAddTags。在 DoAddTags 中放置一个刹车点并检查 _tagsAdded 是否为真。如果是这样,请检查 CallStack 是否从您期望的位置调用。
  • @m.rogalski - DoAddTags 仅从列出的表达式中调用.. 通过查看堆栈来支持。即使在“_tagsAdded || DoAddTags()”上放置断点,当“_tagsAdded == true”时输入DoAddTags

标签: c# visual-studio


【解决方案1】:

此代码不会显示您描述的行为,短路就像描述的那样工作。

实际发生的情况:_tagsAdded 最初是 false,因此调用了 DoAddTags(),将 _tagsAdded 设置为 true

然后调试器启动,您检查 _tagsAdded 并看到它是 true

改为使用 F11 单步执行您的代码并检查或观察所有相关变量。

【讨论】:

  • 对不起,你错了。 1 - 我在 DoAddTags 条目上有一个断点。 2 - 我在 _tagsAdded 上有一个 Watch 3 - 第二次命中断点时,_doAddTags 为真。即,尽管发生短路,但已进入该功能。 4 - 我部门的所有开发人员(20 岁以上)都无法解释这种行为。
  • if (Activity != CIPActivities.AddingOPCTags && !_tagsAdded) 这是 DoAddTags 中的第一行。 _tagsAdded,在第二次重申时为 TRUE。未应用短路,否则不会调用此代码
  • 不,我没看错。 See this Ideone。我正在处理你给我们的东西。如果您不提供minimal reproducible example,则此答案将尽可能接近。你要么有一些线程问题,要么调试器对你撒谎,或者许多其他问题。也许添加一些日志来记录程序中某些点的值。
猜你喜欢
  • 2012-02-10
  • 2021-11-21
  • 2017-09-10
  • 1970-01-01
  • 2012-12-16
  • 2015-11-14
  • 2017-01-21
  • 2010-12-21
相关资源
最近更新 更多