Reputation: 124
I have a Dictionary. I use this code to get the index of the object:
type.Name = _shuffledClasses.Where(entry => entry.Key.Name.Equals(originName))
.Where(entry => entry.Key.Namespace.Equals(type.Namespace))
.Select(item => item.Value).GetEnumerator().Current.Name;
But it doesn't find the Object. I double checked if the Object is create correctly and if it exists, and it does! The Object in question is in the 'Key' column and I wan't to get the object in the 'Value' column.
I tried also this piece of code, which doesn't work aswell:
type.Name = _shuffledClasses[new Classes()
{
Name = originName,
Namespace = type.Namespace
}].Name;
My "Classes" Object looks as follows:
class Classes
{
public string Namespace { get; set; }
public string Name { get; set; }
}
Why wont it find the Object?
I did some research and I tried overriding Equals and GetHashCode, now my class looks like this and still doesn't work:
public override bool Equals(object obj)
{
Classes fooItem = obj as Classes;
return fooItem == this;
}
public override int GetHashCode()
{
return base.GetHashCode();
}
Upvotes: 0
Views: 736
Reputation: 37281
If you are using a Dictionary
the clearest way of finding a Key
in it is by using the []
or by TryGetValue
.
Using linq is great but in my opinion this is not a place to use it. Searching a key
in a dictionary is a o(1)
operation but using linq the way you did turns it to a o(n)
. If you can override the GetHashCode
and Equals
or supply a custom IEquatable<>
I think it is better.
static void Main(string[] args)
{
Dictionary<Classes, string> data = new Dictionary<Classes, string>
{
[new Classes { Name = "a", Namespace = "a" }] = "first",
[new Classes { Name = "b", Namespace = "b" }] = "second",
};
var key = new Classes { Name = "a", Namespace = "a" };
string result1 = data[key]; // "first"
string result2;
if (data.TryGetValue(key, out result2))
{
Console.WriteLine(result2); // 'first"
}
}
class Classes
{
public string Name { get; set; }
public string Namespace { get; set; }
public override bool Equals(object obj)
{
var other = obj as Classes;
if (other == null)
return false;
return other.Name == Name &&
other.Namespace == Namespace;
}
public override int GetHashCode()
{
return Name.GetHashCode() ^
Namespace.GetHashCode();
}
}
The problem with your implementation of the overriding of the methods is:
Equals - after casting you are still not actually comparing the properties
public override bool Equals(object obj)
{
Classes fooItem = obj as Classes;
return fooItem == this;
}
GetHashCode - You gave no implementation to it.. Still using the GetHashCode
of object
public override int GetHashCode()
{
return base.GetHashCode();
}
For further references see:
Upvotes: 2
Reputation: 60266
You code is fundamentally broken right here:
.GetEnumerator().Current.Name;
The enumerator needs to be moved one element ahead with MoveNext()
or Current
will not have any value.
Also, enumerators should be disposed. Try this instead:
type.Name = _shuffledClasses.Where(entry => entry.Key.Name.Equals(originName))
.Where(entry => entry.Key.Namespace.Equals(type.Namespace))
.Select(item => item.Value)
.First().Name;
If you don't want to use First()
for whatever reason, you can also iterate manually like this:
using (var enumerator = _shuffledClasses.Where(entry => entry.Key.Name.Equals(originName))
.Where(entry => entry.Key.Namespace.Equals(type.Namespace))
.Select(item => item.Value).GetEnumerator()) {
enumerator.MoveNext(); // maybe check here if the operation is successful!
type.Name = enumerator.Current.Name;
}
Upvotes: 3
Reputation: 125650
Why wont it find the Object?
Because you didn't override GetHashCode and Equals in your class, which is required for it to work as key in Dictionary and HashSet
Dictionary<TKey, TValue>
requires an equality implementation to determine whether keys are equal. You can specify an implementation of theIEqualityComparer<T>
generic interface by using a constructor that accepts a comparer parameter; if you do not specify an implementation, the default generic equality comparerEqualityComparer<T>.Default
is used. If typeTKey
implements theSystem.IEquatable<T>
generic interface, the default equality comparer uses that implementation.
And this generic comparer uses reference equality if your type does not implement IEquatable<T>
.
You can try using LINQ and First
if you don't want to implement your custom equality, but that will defeat the purpose of using Dictionary<TKey, TValue>
because you'll have to scan the entire collection to get that value:
shuffledClasses.First(x => x.Key.Name == myName && x.Key.Value == myValue).Value
Upvotes: 2