因此,我遇到了一個有趣的問題,即在使用類型爲PhysicalAddress的密鑰時,在C#字典中獲取重複密鑰。這很有趣,因爲它只發生在很長一段時間之後,我不能在一臺完全不同的機器上使用相同的代碼在單元測試中重現它。我可以在Windows XP SP3機器上可靠地重現它,但一次只能讓它運行幾天,即使它只發生一次。使用PhysicalAddress作爲密鑰時字典中的重複密鑰
下面是我使用的代碼,下面是該代碼部分的日誌輸出。
代碼:
private void ProcessMessages()
{
IDictionary<PhysicalAddress, TagData> displayableTags = new Dictionary<PhysicalAddress, TagData>();
while (true)
{
try
{
var message = incomingMessages.Take(cancellationToken.Token);
VipTagsDisappeared tagsDisappeared = message as VipTagsDisappeared;
if (message is VipTagsDisappeared)
{
foreach (var tag in tagDataRepository.GetFromTagReports(tagsDisappeared.Tags))
{
log.DebugFormat(CultureInfo.InvariantCulture, "Lost tag {0}", tag);
RemoveTag(tag, displayableTags);
}
LogKeysAndValues(displayableTags);
PublishCurrentDisplayableTags(displayableTags);
}
else if (message is ClearAllTags)
{
displayableTags.Clear();
eventAggregator.Publish(new TagReaderError());
}
else if (message is VipTagsAppeared)
{
foreach (TagData tag in tagDataRepository.GetFromTagReports(message.Tags))
{
log.DebugFormat(CultureInfo.InvariantCulture, "Detected tag ({0}) with Exciter Id ({1})", tag.MacAddress, tag.ExciterId);
if (tagRules.IsTagRssiWithinThreshold(tag) && tagRules.IsTagExciterValid(tag))
{
log.DebugFormat(CultureInfo.InvariantCulture, "Detected tag is displayable ({0})", tag);
bool elementAlreadyExists = displayableTags.ContainsKey(tag.MacAddress);
if (elementAlreadyExists)
{
displayableTags[tag.MacAddress].Rssi = tag.Rssi;
}
else
{
displayableTags.Add(tag.MacAddress, tag);
}
}
else
{
log.DebugFormat(CultureInfo.InvariantCulture, "Detected tag is not displayable ({0})", tag);
RemoveTag(tag, displayableTags);
}
}
LogKeysAndValues(displayableTags);
PublishCurrentDisplayableTags(displayableTags);
}
else
{
log.WarnFormat(CultureInfo.InvariantCulture, "Received message of unknown type {0}.", message.GetType());
}
}
catch (OperationCanceledException)
{
break;
}
}
}
private void PublishCurrentDisplayableTags(IDictionary<PhysicalAddress, TagData> displayableTags)
{
eventAggregator.Publish(new CurrentDisplayableTags(displayableTags.Values.Distinct().ToList()));
}
private void RemoveTag(TagData tag, IDictionary<PhysicalAddress, TagData> displayableTags)
{
displayableTags.Remove(tag.MacAddress);
// Now try to remove any duplicates and if there are then log it out
bool removalWasSuccesful = displayableTags.Remove(tag.MacAddress);
while (removalWasSuccesful)
{
log.WarnFormat(CultureInfo.InvariantCulture, "Duplicate tag removed from dictionary: {0}", tag.MacAddress);
removalWasSuccesful = displayableTags.Remove(tag.MacAddress);
}
}
private void LogKeysAndValues(IDictionary<PhysicalAddress, TagData> displayableTags)
{
log.TraceFormat(CultureInfo.InvariantCulture, "Keys");
foreach (var physicalAddress in displayableTags.Keys)
{
log.TraceFormat(CultureInfo.InvariantCulture, "Address: {0}", physicalAddress);
}
log.TraceFormat(CultureInfo.InvariantCulture, "Values");
foreach (TagData physicalAddress in displayableTags.Values)
{
log.TraceFormat(CultureInfo.InvariantCulture, "Address: {0} Name: {1}", physicalAddress.MacAddress, physicalAddress.Name);
}
}
和處理消息的使用步驟如下:
Thread processingThread = new Thread(ProcessMessages);
GetFromTagReports代碼
public IEnumerable<TagData> GetFromTagReports(IEnumerable<TagReport> tagReports)
{
foreach (var tagReport in tagReports)
{
TagData tagData = GetFromMacAddress(tagReport.MacAddress);
tagData.Rssi = tagReport.ReceivedSignalStrength;
tagData.ExciterId = tagReport.ExciterId;
tagData.MacAddress = tagReport.MacAddress;
tagData.Arrived = tagReport.TimeStamp;
yield return tagData;
}
}
public TagData GetFromMacAddress(PhysicalAddress macAddress)
{
TagId physicalAddressToTagId = TagId.Parse(macAddress);
var personEntity = personFinder.ByTagId(physicalAddressToTagId);
if (personEntity.Person != null && !(personEntity.Person is UnknownPerson))
{
return new TagData(TagType.Person, personEntity.Person.Name);
}
var tagEntity = tagFinder.ByTagId(physicalAddressToTagId);
if (TagId.Invalid == tagEntity.Tag)
{
return TagData.CreateUnknownTagData(macAddress);
}
var equipmentEntity = equipmentFinder.ById(tagEntity.MineSuiteId);
if (equipmentEntity.Equipment != null && !(equipmentEntity.Equipment is UnknownEquipment))
{
return new TagData(TagType.Vehicle, equipmentEntity.Equipment.Name);
}
return TagData.CreateUnknownTagData(macAddress);
}
在其中創建物理地址
var physicalAddressBytes = new byte[6];
ByteWriter.WriteBytesToBuffer(physicalAddressBytes, 0, protocolDataUnit.Payload, 4, 6);
var args = new TagReport
{
Version = protocolDataUnit.Version,
MacAddress = new PhysicalAddress(physicalAddressBytes),
BatteryStatus = protocolDataUnit.Payload[10],
ReceivedSignalStrength = IPAddress.NetworkToHostOrder(BitConverter.ToInt16(protocolDataUnit.Payload, 12)),
ExciterId = IPAddress.NetworkToHostOrder(BitConverter.ToInt16(protocolDataUnit.Payload, 14))
};
public static void WriteBytesToBuffer(byte[] oldValues, int oldValuesStartindex, byte[] newValues, int newValuesStartindex, int max)
{
var loopmax = (max > newValues.Length || max < 0) ? newValues.Length : max;
for (int i = 0; i < loopmax; ++i)
{
oldValues[oldValuesStartindex + i] = newValues[newValuesStartindex + i];
}
}
注意以下幾點:
- Every在messages.Tags '標籤' 包含 '新' PhysicalAddress。
- 返回的每個TagData也是「新」。
- 'tagRules'方法不會以任何方式修改傳入的'標記'。
- 嘗試將PhysicalAddress的兩個實例(從相同字節創建)放入Dictionary中進行單獨測試時會拋出'KeyAlreadyExists'異常。
- 我也試過TryGetValue,它產生了相同的結果。
日誌輸出,其中一切都很好:
2013-04-26 18:28:34,347 [8] DEBUG ClassName - Detected tag (000CCC756081) with Exciter Id (0)
2013-04-26 18:28:34,347 [8] DEBUG ClassName - Detected tag is displayable (Unknown: ?56081)
2013-04-26 18:28:34,347 [8] TRACE ClassName - Keys
2013-04-26 18:28:34,347 [8] TRACE ClassName - Address: 000CCC755898
2013-04-26 18:28:34,347 [8] TRACE ClassName - Address: 000CCC756081
2013-04-26 18:28:34,347 [8] TRACE ClassName - Address: 000CCC755A27
2013-04-26 18:28:34,347 [8] TRACE ClassName - Address: 000CCC755B47
2013-04-26 18:28:34,347 [8] TRACE ClassName - Values
2013-04-26 18:28:34,347 [8] TRACE ClassName - Address: 000CCC755898 Name: Scotty McTester
2013-04-26 18:28:34,347 [8] TRACE ClassName - Address: 000CCC756081 Name: ?56081
2013-04-26 18:28:34,347 [8] TRACE ClassName - Address: 000CCC755A27 Name: JDTest1
2013-04-26 18:28:34,347 [8] TRACE ClassName - Address: 000CCC755B47 Name: 33 1
2013-04-26 18:28:34,347 [8] TRACE ClassName - Current tags: Scotty McTester, ?56081, JDTest1, 33 1
日誌輸出,其中我們得到了重複鍵:
2013-04-26 18:28:35,608 [8] DEBUG ClassName - Detected tag (000CCC756081) with Exciter Id (0)
2013-04-26 18:28:35,608 [8] DEBUG ClassName - Detected tag is displayable (Unknown: ?56081)
2013-04-26 18:28:35,608 [8] TRACE ClassName - Keys
2013-04-26 18:28:35,608 [8] TRACE ClassName - Address: 000CCC755898
2013-04-26 18:28:35,608 [8] TRACE ClassName - Address: 000CCC756081
2013-04-26 18:28:35,618 [8] TRACE ClassName - Address: 000CCC755A27
2013-04-26 18:28:35,618 [8] TRACE ClassName - Address: 000CCC755B47
2013-04-26 18:28:35,618 [8] TRACE ClassName - Address: 000CCC756081
2013-04-26 18:28:35,618 [8] TRACE ClassName - Values
2013-04-26 18:28:35,618 [8] TRACE ClassName - Address: 000CCC755898 Name: Scotty McTester
2013-04-26 18:28:35,618 [8] TRACE ClassName - Address: 000CCC756081 Name: ?56081
2013-04-26 18:28:35,648 [8] TRACE ClassName - Address: 000CCC755A27 Name: JDTest1
2013-04-26 18:28:35,648 [8] TRACE ClassName - Address: 000CCC755B47 Name: 33 1
2013-04-26 18:28:35,648 [8] TRACE ClassName - Address: 000CCC756081 Name: ?56081
2013-04-26 18:28:35,648 [8] TRACE ClassName - Current tags: Scotty McTester, ?56081, JDTest1, 33 1, ?56081
注意,一切都在單個線程發生(見[8 ]),所以字典沒有被同時修改的機會。摘錄來自相同的日誌和相同的流程實例。另外請注意,在第二組日誌中,我們最終得到兩個相同的密鑰!
我在看什麼:我已經將PhysicalAddress更改爲字符串,以查看我是否可以從嫌疑犯名單中刪除該名字。
我的問題是:
- 有沒有,我不是在上面的代碼中看到一個問題嗎?
- PhysicalAddress上的等號方法有問題嗎? (現在只有錯誤?)
- 字典有問題嗎?
您可以注意到非工作運行不會在同一時間發生。這可能是線程有問題的一個論據。你怎麼能確定'displayableTags'不是一個共享對象?這是一個局部變量嗎?屬性?此外,使用'TryGetValue'而不是'ContainsKey'。 – 2013-04-29 07:49:55
我可以肯定,因爲'displayableTags'是在Thread構造函數調用的方法中創建的本地創建的變量。我嘗試過TryGetValue,它做了同樣的事情(我將它添加到問題中)。此外,從TryGetValue在MSDN DOCO: _this方法結合了ContainsKey方法的功能和項目property._ – JohnDRoach 2013-04-29 07:57:37
你能在一個塊張貼代碼?問題可能在於你的日誌功能,我們可以看到嗎? – 2013-04-29 08:01:38