为什么这个 if 语句不能正常工作
Why doesn't this if statement work properly
此代码旨在在邮箱再水化后执行清理(来自 Symantec Enterprise Vault)。我们在重新水化之前对邮箱中所有项目的 MessageId
和 ConversationId
进行快照索引。
补水后这段代码
if (string.Equals(item.ItemClass, "IPM.Note.EnterpriseVault.Shortcut", StringComparison.InvariantCulture) || ((existingIds.Any(x => x.ConversationId == item.ConversationId.ToString()) == false || (item.ItemClass == "IPM.Appointment" && existingIds.Any(x => x.MessageId == item.Id.ToString()) == false) && item.DateTimeReceived < snapshotDate)))
{
item.Delete(DeleteMode.HardDelete);
}
应该删除
- 任何
ItemClass
为 "IPM.Note.EnterpriseVault.Shortcut" 的项目
- 具有
ItemClass
的 "IPM.Appointment" 的任何项目,其中 Id
不在 MessageId
的 existingIds
列表中,除非已收到在`snapshotDate 之后
- 任何其他
ConversationId
不在 existingIds
列表中的项目,除非它们是在 snapshotDate
之后收到的。
在 运行 这段代码之后,一位用户报告丢失了一些在 snapshotDate
之后收到的电子邮件,所以看来我的 if
声明有误! :( 有人可以告诉我我出了什么问题(或者我可以分解它以更好地理解它的方法)以及这段代码实际上做了什么所以我可以让用户知道丢失了什么。我知道 lofical OR 是出了名的难写,我想我在某处的括号里弄错了,但我就是看不到它。
我发现查看此类问题的最简单方法是使用大量换行符和缩进。我在每个 (
之后添加一个中断并增加缩进(除了琐碎的 ()
),将匹配的 )
放在它们的匹配对下方,并将运算符放在它们要加入的项目之间的单独行上:
if (
string.Equals(
item.ItemClass,
"IPM.Note.EnterpriseVault.Shortcut", StringComparison.InvariantCulture
)
||
(
(
existingIds.Any(
x => x.ConversationId == item.ConversationId.ToString()
) == false
||
(
item.ItemClass == "IPM.Appointment"
&&
existingIds.Any(
x => x.MessageId == item.Id.ToString()
) == false
)
&&
item.DateTimeReceived < snapshotDate
)
)
)
{
item.Delete(DeleteMode.HardDelete);
}
我可以立即发现两件事 - 一对括号只包含另一对括号,并且 &&
和 ||
同时出现 "level" 所以我们是依赖运算符优先级。
我猜你想要 &&
在内括号之外,这样它既适用于约会检查,也适用于现有的 ID。例如。改为:
if (
string.Equals(
item.ItemClass,
"IPM.Note.EnterpriseVault.Shortcut", StringComparison.InvariantCulture
)
||
(
(
existingIds.Any(
x => x.ConversationId == item.ConversationId.ToString()
) == false
||
(
item.ItemClass == "IPM.Appointment"
&&
existingIds.Any(
x => x.MessageId == item.Id.ToString()
) == false
)
)
&&
item.DateTimeReceived < snapshotDate
)
)
{
item.Delete(DeleteMode.HardDelete);
}
(一旦您确认所有内容都符合您的需要,您可以折叠回更少的行)
如果检查到本地函数,我会建议您拆分,这样调试起来会容易得多。
if (IsShourtcut(item) || NotExistingAppItment(item) || ExistingConversation(item) && IsReceivedBeforSnapshot(item))
{
// to delete
}
bool IsShourtcut(Item item) => string.Equals(item.ItemClass, "IPM.Note.EnterpriseVault.Shortcut", StringComparison.InvariantCulture);
bool NotExistingAppItment(Item item) => item.ItemClass == "IPM.Appointment" && existingIds.All(x => x.MessageId != item.Id.ToString());
bool ExistingConversation(Item item) => existingIds.All(x => x.ConversationId != item.ConversationId.ToString();
bool IsReceivedBeforSnapshot(Item item) => item.DateTimeReceived < snapshotDate;
其他两个答案都非常有帮助,我也相应地投了赞成票。然而,我认为我会 post 我的最终解决方案受到 and 的启发,特别依赖 OxQ 推荐的局部函数的使用。我现在已经编写了单元测试(我应该早点完成)并且这些都使用我的新方法通过了,而其中五个之前失败了。我相信这段代码更符合所陈述的问题,并且非常易于阅读和理解。我不得不使用标量值而不是整个 Item
对象,因此我可以对它进行单元测试,因为 Exchange Web 服务托管 API 不使用接口。
switch (itemClass)
{
case "IPM.Note.EnterpriseVault.Shortcut":
return true;
case "IPM.Appointment":
return NotExistingMessage() && IsReceivedBeforeSnapshot();
default:
return NotExistingConversation() && IsReceivedBeforeSnapshot();
}
bool NotExistingMessage() => existingIds.All(x => x.MessageId != messageId);
bool NotExistingConversation() => existingIds.All(x => x.ConversationId != conversationId);
bool IsReceivedBeforeSnapshot() => dateTimeReceived < uploadDate;
此代码旨在在邮箱再水化后执行清理(来自 Symantec Enterprise Vault)。我们在重新水化之前对邮箱中所有项目的 MessageId
和 ConversationId
进行快照索引。
补水后这段代码
if (string.Equals(item.ItemClass, "IPM.Note.EnterpriseVault.Shortcut", StringComparison.InvariantCulture) || ((existingIds.Any(x => x.ConversationId == item.ConversationId.ToString()) == false || (item.ItemClass == "IPM.Appointment" && existingIds.Any(x => x.MessageId == item.Id.ToString()) == false) && item.DateTimeReceived < snapshotDate)))
{
item.Delete(DeleteMode.HardDelete);
}
应该删除
- 任何
ItemClass
为 "IPM.Note.EnterpriseVault.Shortcut" 的项目
- 具有
ItemClass
的 "IPM.Appointment" 的任何项目,其中Id
不在MessageId
的existingIds
列表中,除非已收到在`snapshotDate 之后
- 任何其他
ConversationId
不在existingIds
列表中的项目,除非它们是在snapshotDate
之后收到的。
在 运行 这段代码之后,一位用户报告丢失了一些在 snapshotDate
之后收到的电子邮件,所以看来我的 if
声明有误! :( 有人可以告诉我我出了什么问题(或者我可以分解它以更好地理解它的方法)以及这段代码实际上做了什么所以我可以让用户知道丢失了什么。我知道 lofical OR 是出了名的难写,我想我在某处的括号里弄错了,但我就是看不到它。
我发现查看此类问题的最简单方法是使用大量换行符和缩进。我在每个 (
之后添加一个中断并增加缩进(除了琐碎的 ()
),将匹配的 )
放在它们的匹配对下方,并将运算符放在它们要加入的项目之间的单独行上:
if (
string.Equals(
item.ItemClass,
"IPM.Note.EnterpriseVault.Shortcut", StringComparison.InvariantCulture
)
||
(
(
existingIds.Any(
x => x.ConversationId == item.ConversationId.ToString()
) == false
||
(
item.ItemClass == "IPM.Appointment"
&&
existingIds.Any(
x => x.MessageId == item.Id.ToString()
) == false
)
&&
item.DateTimeReceived < snapshotDate
)
)
)
{
item.Delete(DeleteMode.HardDelete);
}
我可以立即发现两件事 - 一对括号只包含另一对括号,并且 &&
和 ||
同时出现 "level" 所以我们是依赖运算符优先级。
我猜你想要 &&
在内括号之外,这样它既适用于约会检查,也适用于现有的 ID。例如。改为:
if (
string.Equals(
item.ItemClass,
"IPM.Note.EnterpriseVault.Shortcut", StringComparison.InvariantCulture
)
||
(
(
existingIds.Any(
x => x.ConversationId == item.ConversationId.ToString()
) == false
||
(
item.ItemClass == "IPM.Appointment"
&&
existingIds.Any(
x => x.MessageId == item.Id.ToString()
) == false
)
)
&&
item.DateTimeReceived < snapshotDate
)
)
{
item.Delete(DeleteMode.HardDelete);
}
(一旦您确认所有内容都符合您的需要,您可以折叠回更少的行)
如果检查到本地函数,我会建议您拆分,这样调试起来会容易得多。
if (IsShourtcut(item) || NotExistingAppItment(item) || ExistingConversation(item) && IsReceivedBeforSnapshot(item))
{
// to delete
}
bool IsShourtcut(Item item) => string.Equals(item.ItemClass, "IPM.Note.EnterpriseVault.Shortcut", StringComparison.InvariantCulture);
bool NotExistingAppItment(Item item) => item.ItemClass == "IPM.Appointment" && existingIds.All(x => x.MessageId != item.Id.ToString());
bool ExistingConversation(Item item) => existingIds.All(x => x.ConversationId != item.ConversationId.ToString();
bool IsReceivedBeforSnapshot(Item item) => item.DateTimeReceived < snapshotDate;
其他两个答案都非常有帮助,我也相应地投了赞成票。然而,我认为我会 post 我的最终解决方案受到 Item
对象,因此我可以对它进行单元测试,因为 Exchange Web 服务托管 API 不使用接口。
switch (itemClass)
{
case "IPM.Note.EnterpriseVault.Shortcut":
return true;
case "IPM.Appointment":
return NotExistingMessage() && IsReceivedBeforeSnapshot();
default:
return NotExistingConversation() && IsReceivedBeforeSnapshot();
}
bool NotExistingMessage() => existingIds.All(x => x.MessageId != messageId);
bool NotExistingConversation() => existingIds.All(x => x.ConversationId != conversationId);
bool IsReceivedBeforeSnapshot() => dateTimeReceived < uploadDate;