Retrieved Dictionary Key Not Found - c#

I have a SortedDictionary declared like such:
SortedDictionary<MyObject,IMyInterface> dict = new SortedDictionary<MyObject,IMyInterface>();
When its populated with values, if I grab any key from the dictionary and then try to reference it immediately after, I get a KeyNotFoundException:
MyObject myObj = dict.Keys.First();
var value = dict[myObj]; // This line throws a KeyNotFoundException
As I hover over the dictionary (after the error) with the debugger, I can clearly see the same key that I tried to reference is in fact contained in the dictionary. I'm populating the dictionary using a ReadOnlyCollection of MyObjects. Perhaps something odd is happening there? I tried overriding the == operator and Equals methods to get the explicit comparison I wanted, but no such luck. That really shouldn't matter since I'm actually getting a key directly from the Dictionary then querying the Dictionary using that same key. I can't figure out what's causing this. Has anyone ever seen this behavior?
EDIT 1
In overriding Equals I also overloaded (as MS recommends) GetHashCode as well. Here's the implementation of MyObject for anyone interested:
public class MyObject
{
public string UserName { get; set;}
public UInt64 UserID { get; set;}
public override bool Equals(object obj)
{
if (obj == null || GetType()!= obj.GetType())
{
return false;
}
// Return true if the fields match:
return this.Equals((MyObject)obj);
}
public bool Equals(MyObject other)
{
// Return true if the fields match
return this.UserID == other.UserID;
}
public override int GetHashCode()
{
return (int)this.UserID;
}
public static bool operator ==( MyObject a, MyObject b)
{
// If both are null, or both are same instance, return true.
if (System.Object.ReferenceEquals(a, b))
{
return true;
}
// If one is null, but not both, return false.
if (((object)a == null) || ((object)b == null))
{
return false;
}
// Return true if the fields match:
return a.UserID == b.UserID
}
public static bool operator !=( MyObject a, MyObject b)
{
return !(a == b);
}
}
What I noticed from debugging is that if I add a quick watch (after the KeyNotFoundException is thrown) for the expression:
dict.ElementAt(0).Key == value;
it returns true. How can this be?
EDIT 2
So the problem ended up being because SortedDictionary (and Dictionary as well) are not thread-safe. There was a background thread that was performing some operations on the dictionary which seem to be triggering a resort of the collection (adding items to the collection would do this). At the same time, when the dictionary iterated through the values to find my key, the collection was being changed and it was not finding my key even though it was there.
Sorry for all of you who asked for code on this one, I'm currently debugging an application that I inherited and I didn't realize this was going on on a timed, background thread. As such, I thought I copied and pasted all the relevant code, but I didn't realize there was another thread running behind everything manipulating the collection.

It appears that the problem ended up being because SortedDictionary is not thread-safe. There was a background thread that was performing some operations on the dictionary (adding items to the collection) which seems to be triggering a resort of the collection. At the same time, when the dictionary was attempting to iterate through the values to find my key, the collection was being changed and resorted, rendering the enumerator invalid, and it was not finding my key even though it was there.

I have a suspicion - it's possible that you're changing the UserID of the key after insertion. For example, this would demonstrate the problem:
var key = new MyObject { UserId = 10 };
var dictionary = new Dictionary<MyObject, string>();
dictionary[key] = "foo";
key.UserId = 20; // This will change the hash code
var value = dict[key]; // Bang!
You shouldn't change properties involved in equality/hash-code considerations for an object which is being used as the key in a hash-based collection. Ideally, change your code so that this can't be changed - make UserId readonly, initialized on construction.
The above definitely would cause a problem - but it's possible that it's not the same as the problem you're seeing, of course.

In addition to overloading == and Equals, make sure you override GetHashCode with a suitable hash function. In particular, see this specification from the documentation:
If two objects compare as equal, the GetHashCode method for each object must return the same value. However, if two objects do not
compare as equal, the GetHashCode methods for the two objects do not
have to return different values.
The GetHashCode method for an object must consistently return the same hash code as long as there is no modification to the object state
that determines the return value of the object's Equals method. Note
that this is true only for the current execution of an application,
and that a different hash code can be returned if the application is
run again.
For the best performance, a hash function should generate an even distribution for all input, including input that is heavily clustered.
An implication is that small modifications to object state should
result in large modifications to the resulting hash code for best hash
table performance.
Hash functions should be inexpensive to compute.
The GetHashCode method should not throw exceptions.
I agree with Jon Skeet's suspicion that you're somehow unintentionally modifying UserID property after it's added as a key. But since the only property that's important for testing equality in MyObject is UserID (and therefore that's the only property that the Dictionary cares about), I'd recommend refactoring your code to use a simple Dictionary<ulong, IMyInterface> instead:
Dictionary<ulong, IMyInterface> dict = new Dictionary<string, IMyInterface>();
ulong userID = dict.Keys.First();
var value = dict[userID];

Related

Dictionary error "KeyNotFound" when accessing my accessors

I am getting a
'System.Collections.Generic.KeyNotFoundException' occurred in mscorlib.dll
when i run my code, everthing seems to be fine, i have been unable to find the bug. Here is path of my class caling my get/set
foreach (Tran transaction in transactions)
{
Account sAcc = items[transaction.ID1];//getting error here
Account dAcc = items[transaction.ID2];
decimal tempResult = sAcc.Money - transaction.Amount;
foreach (char s in sAcc.BorP)
Console.WriteLine(s);
And here is my get/set class
public class Tran
{
public int ID1 { get; set; }
public int ID2 { get; set; }
public decimal Amount { get; set; }
}
It was running before and i ran some more test and i keep getting this error and dont know what could be causing int. Thanks for you help
You can use the TryGetValue method of the dictionary.
Here is a sample code of using
object result; // Un-Initialized instance result
myCollection.TryGetValue("Test", out result); // If the key exists the method will out the value
Grabbed from another SO post.
From MSDN's entry on Dictionary.TryGetValue Method:
This method combines the functionality of the ContainsKey method and
the Item property.
If the key is not found, then the value parameter gets the appropriate
default value for the value type TValue; for example, 0 (zero) for
integer types, false for Boolean types, and null for reference types.
Use the TryGetValue method if your code frequently attempts to access
keys that are not in the dictionary. Using this method is more
efficient than catching the KeyNotFoundException thrown by the Item
property.
This method approaches an O(1) operation.
Also reference in this post to lookup the performance of Indexer vs TryGetValue
What is more efficient: Dictionary TryGetValue or ContainsKey+Item?
The issue you are having is that the items you are trying to read from the items array don't exist.
Use either
if (items.ContainsKey(transaction.ID1) && items.ContainsKey(transaction.ID2))
{
// Your code.
} else {
// Signal an error.
}
Or if you have a default account class that you want to use when the transactions do not exist you could use something like this.
if (!items.TryGetValue(transaction.ID1, out sAcc))
items.Add(transaction.ID1, sAcc = new Account);
if (!items.TryGetValue(transaction.ID2, out dAcc))
items.Add(transaction.ID2, dAcc = new Account);
// Your code.
Otherwise if the transaction ID:s should always be in item the problem with your code is likely outside of the code snippets you shared here. I would check what the ID:s are you are trying to look up and do a sanity check.

Remove one list from another mvc

I have two lists of the same type and I am trying to subtract the information in one list from the other and then save the result into the model.
I have tried two ways of doing it and so far I can't get either to work:
These are the two lists:
List<ApplicationsDetailsModel> AppList = ctx.Database.SqlQuery<ApplicationsDetailsModel>("exec get_applications_r").ToList();
var AppExceptionList = new List<ApplicationsDetailsModel>();
foreach(var g in AnIrrelevantList)
{
AppExceptionList.Add(new ApplicationsDetailsModel()
{
AppNum = g.AppNum,
AppName = g.AppName
});
}
So they now both have different data in the same format.
model.AppList = AppList.Except(AppExceptionList).ToList();
This doesn't bring up any errors but it also doesn't subtract the second list from the first.
var onlyInFirst = AppList.RemoveAll(a => AppExceptionList.Any(b => AppList == AppExceptionList));
I got this idea from this question.
Anyone know where I am going wrong?
The instances are not the same and are therefore not found to be equal by Except since it's checking for reference equal (which is obviously never going to be the case). For your situation you need to write a custom equality comparer... I've taken a stab at it here...
public class ApplicationsDetailsModelEqualityComparer : IEqualityComparer<ApplicationsDetailsModel>
{
public bool Equals(ApplicationsDetailsModel x, ApplicationsDetailsModel y)
{
return x.AppNum == y.AppNum && x.AppName == y.AppName;
}
public int GetHashCode(ApplicationsDetailsModel obj)
{
int hashCode = (obj.AppName != null ? obj.AppName.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ obj.AppNum.GetHashCode();
return hashCode;
}
}
Usage...
model.AppList = AppList.Except(AppExceptionList, new ApplicationsDetailsModelEqualityComparer()).ToList();
Note that I'm assuming your AppNum and AppName together uniquely identify your objects in your list.
The Except method doesn't know how to compare two objects of type ApplicationsDetailsModel. You need to tell him explicitly, using an IEqualityComparer :
public class ApplicationsDetailsModelComparer : IEqualityComparer<ApplicationsDetailsModel> {
public bool Equals(ApplicationsDetailsModel first, ApplicationsDetailsModel second) {
return first.AppNum == second.AppNum;
}
public int GetHashCode(ApplicationsDetailsModel applicationsDetailsModel) {
return applicationsDetailsModel.AppNum.GetHashCode();
}
}
Then, you use it like this :
model.AppList = AppList.Except(AppExceptionList, new ApplicationsDetailsModelComparer ()).ToList();
If AppNum isn't an unique value in your collection (like a primary key), feel free to adapt the comparer class to your needs.
jgauffin's answer on the question that you linked to sums it up:
http://stackoverflow.com/a/13361682/89092
Except requires that Equals and GetHashCode is implemented in the traversed class.
The problem is that the Except method does not now how to compare instances of ApplicationsDetailsModel
You should implement GetHashCode in ApplicationsDetailsModel to create a way to uniquely identify an instance
You should implement Equals in ApplicationsDetailsModel and use the result of GetHashCode to return whether or no the instances should be considered "Equal". It is probably best to do this by implementing the IEquatable interface: http://msdn.microsoft.com/en-us/library/ms131187(v=vs.110).aspx
When you perform these steps, the Except method will work as expected

Enum equality (and EventHandlerList's keys)

Subtitle: Can EventHandlerList key's Type be something else than object?
I wanted to use an enum store the keys I would like to have in an EventHandler.
public enum EventKey
{
OnBark, OnCry
}
public EventHandlerList EventList = new EventHandlerList();
public event ComplaintEventHandler OnBark
{
add
{
EventList.AddHandler(EventKey.OnBark, value);
}
remove
{
EventList.RemoveHandler(EventKey.OnBark, value);
}
}
var handler = EventList[eventKey] as ComplaintEventHandler;
>
handler = null
As it turns out it does not work. But it works if I use keys declared like (as shown on):
static object EventKeyOnTap = new object();
After reading some mscorlib's code I see that the problem comes from next.key == key in
private EventHandlerList.ListEntry Find(object key)
{
EventHandlerList.ListEntry next = this.head;
while (next != null && next.key != key)
{
next = next.next;
}
return next;
}
Both compared keys are from my Enum, but they are not equal!
I guess it comes from some implicit casts to object happening (the key stored in the list is of type object) but am not fluent enough with such low-level concepts.
Is my guess right?
What is the best way to use an Enum as a key in an EventHandlerList?
For now I will create my own EventHandlerList with Enum as key Type.
For now I created my own EventHandlerList with a constructor taking a Func<object, object, bool> which I then use in place of the equality comparaison aforementioned.
Try this code. Can you explain output?
var bark1 = (object)EventKey.OnBark;
var bark2 = (object)EventKey.OnBark;
Console.WriteLine(bark1 != bark2);
Console.WriteLine(bark1.Equals(bark2));
If yes, I don't know why you asked this question. If no, you definitely should get aware of value types, reference types and boxing.
In short, AddHandler method accepts object parameter, hence your key (which is value type) is boxed when you call:
EventList.AddHandler(EventKey.OnBark, value);
If you call this method twice with the same enum key, key will be boxed twice, and two different objects in heap will be actually created.
That's why this check next.key != key inside Find method fails (it compares addresses of two separate objects in heap).
EventHandlerList is sealed class, so you cannot affect its guts, but in your own code you could handle this situation with better check:
next.key.Equals(key)

C# optimal IDictionary usage for lookup with possibility of not found

Let's say I have a method as follows:
internal MyClass GetValue(long key)
{
if (_myDictionary.ContainsKey(key))
return _myDictionary[key];
return null; // Not found
}
IDictionary<long,MyClass> _myDictionary=...
But the above code has two lookups in the dictionary:
The test for the existance of the key
The actual retrieval of the value
Is there a more optimal way to phrase such a function, so that only one lookup is performed, but the case of "not found" is still handled via a null return (i.e., not via a not found exception)?
For example, it would have been nice if the lookup for the key returned some sort of iterator that could be used to retrieve the value or an invalid iterator if the value was not found as is done in C++. Perhaps C# has a better way of doing this given its language features.
The TryGetValue method was designed for precisely this scenario - to avoid the two lookup operations.
This method combines the functionality of the ContainsKey method and
the Item property.
If the key is not found, then the value parameter gets the appropriate
default value for the value type TValue.
[...] Use the TryGetValue method if your code frequently attempts to access
keys that are not in the dictionary. Using this method is more
efficient than catching the KeyNotFoundException thrown by the Item
property.
internal MyClass GetValue(long key)
{
MyClass maybeValue;
// Normally, one would inspect the return value of this method
// but in this case, it's not necessary since a failed lookup
// will set the out argument to default(valType), which is null
// for a reference type - exactly what you want.
_myDictionary.TryGetValue(key, out maybeValue);
return maybeValue;
}
typing up SPFiredrakes idea ...
public static class Extensions
{
public static TValue GetValueOrDefault<TKey, TValue>(
this IDictionary<Tkey, TValue> iDictionary, Tkey key)
{
TValue result;
return iDictionary.TryGetValue(key, out result) ? result : default(TValue)
}
}
used like this
var d = new Dictionary<long, SomeType>
{{1, new SomeType()}, {42, new SomeType()}, ...}
var value1 = d.GetValueOrDefault(1);
var value42 = d.GetValueOrDefault(42);
var valueX = d.GetValueOrDefault(10);
Of course, you should now check to see if your values are null, which may be why the .Net team omitted this feature.
You should use TryGetValue instead - it uses a single lookup.
internal MyClass GetValue(long key) {
MyClass res = null;
_myDictionary.TryGetValue(key, out res)
return res;
}
The call is short enough to use "inline", without adding a wrapper function. TryGetValue returns a bool indicating if the lookup has been successful or not.

Why ReferenceEquals and == operator behave different from Equals

I have an Entity that doesn't override any of the equality members\operators.
When comparing two proxies of them (I got them from the Nhibernate session) the result changes according to the equality method:
ReferenceEquals(first, second) - false.
first == second - false
Equals(first, second) - true.
This is even more weird as they both exist in the same session context and according to the Nhibernate docs:
NHibernate only guarantees identity ( a == b , the default
implementation of Equals()) inside a single ISession!`
And:
The instance is currently associated with a persistence context. It
has a persistent identity (primary key value) and, perhaps, a
corresponding row in the database. For a particular persistence
context, NHibernate guarantees that persistent identity is equivalent
to CLR identity (in-memory location of the object).
So why not all of the equality methods return true?
Update:
I get the enteties this way, Query the session for ChildEntity and get the Parents Entities with Linq's select, similar to this:
var childs = session.Query<Child>();
var parents = childs.Select(x => x.ParentEntity).ToList();
Edit
You might be using a struct? See below
I suppose reference types show the behaviour you expect:
public class Program {
class X { int x,y; }
public static void Main(string[] args)
{
X a = new X();
X b = new X();
System.Console.WriteLine(a == b);
System.Console.WriteLine(a.Equals(b));
System.Console.WriteLine(Equals(a,b));
System.Console.WriteLine(ReferenceEquals(a,b));
} }
Prints:
False
False
False
False
For structs, things are different (commeting out the a==b test, which doesn't compile for structs:)
public class Program {
struct X { int x,y; }
public static void Main(string[] args)
{
X a = new X();
X b = new X();
//System.Console.WriteLine(a == b);
System.Console.WriteLine(a.Equals(b));
System.Console.WriteLine(Equals(a,b));
System.Console.WriteLine(ReferenceEquals(a,b));
} }
Output:
True
True
False
Rationale:
The default implementation of Equals() comes from class ValueType, which is implicit base class of all value types. You may override this implementation by defining your own Equals() method in your struct. ValueType.Equals() always returns false when one compares objects of different (dynamic) types. If objects are of the same type, it compares them by calling Equals() for each field. If any of these returns false, the whole process is stopped, and final result is false. If all field-by-field comparisons return true, final result is true
If ReferenceEquals returns false, you are clearly comparing two different instances.
Equals might still be true if it's overridden, but I don't think that's where the actual problem is.
I'd like to know how you're mapping and getting those objects, because as the docs say, you can never get two different objects of the same type representing the same row in the same session.
After I get childs from the session I Merge them with the session.
var childs = session.Query<Child>();
// Do some stuff
foreach (var child in childs)
{
session.Merge(child);
}
var parents = childs.Select(x => x.ParentEntity).ToList();
It appear that the merge detached the entity from the session and return a new Proxy attached to the session.
It can be fixed with
var newChild = (Child)session.Merge(child);
// Or:
session.Update(child); // (We have session.Clear() in our tests so I can't use this because it makes troubles when you update detached Entity

Categories

Resources