使用||运营商,微软介绍了这里短路评价Short Circuit EvaluationVisual Studio C#和短路评估
不过,我有以下的代码,这似乎违背了这一过程:
if ((_opcLoaded || DoLoadOPC()) &&
(_tagsAdded || DoAddTags()) &&
DoWriteRecipe() &&
(DoResume()))
我试图阻止来自被称为如果_tagsAdded功能DoAddTags是真实的(DoAddTags设置_tagsAdded为true)。
但是,我发现即使在_tagsAdded
为真时也会调用DoAddTag
。 _opcLoaded
和DoLoadOPC
的情况也是如此。我必须在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。
那么我现在看到的是,所有的手表/调试信息是一致的是,DoAddTags被调用,同时_tagsAdded ==真
很难揭开这个表达式的可能的副作用。只要不写不可读的代码,这需要更多的if语句。 –
无法重现您的问题中指定的行为。你确定这些字段之前没有设置为false吗? –
你确定DoAddTags被调用吗?也许它是从其他地方调用的。我检查了Debug,如果_tagsAdded为true,则不会调用DoAddTags。在DoAddTags中放置一个刹车点并检查_tagsAdded是否为真。如果是这样,请检查CallStack是否从您期望的位置调用。 –