Before I start, I'd like to clarify that this is not like all the other somewhat "similar" questions out there. I've tried implementing each approach, but the phenomena I am getting here are really weird.
I have a dictionary where ContainsKey always returns false, even if their GetHashCode functions return the same output, and even if their Equals method returns true.
What could this mean? What am I doing wrong here?
Additional information
The two elements I am inserting are both of type Owner, with no GetHashCode or Equals method. These inherit from a type Storable, which then implements an interface, and also has GetHashCode and Equals defined.
Here's my Storable class. You are probably wondering if the two Guid properties are indeed equal - and yes, they are. I double-checked. See the sample code afterwards.
public abstract class Storable : IStorable
{
public override int GetHashCode()
{
return Id == default(Guid) ? 0 : Id.GetHashCode();
}
public override bool Equals(object obj)
{
var other = obj as Storable;
return other != null && (other.Id == Id || ReferenceEquals(obj, this));
}
public Guid Id { get; set; }
protected Storable()
{
Id = Guid.NewGuid();
}
}
Now, here's the relevant part of my code where the dictionary stuff occurs. It takes in a Supporter object which has a link to an Owner.
public class ChatSession : Storable, IChatSession
{
static ChatSession()
{
PendingSupportSessions = new Dictionary<IOwner, LinkedList<IChatSession>>();
}
private static readonly IDictionary<IOwner, LinkedList<IChatSession>> PendingSupportSessions;
public static ChatSession AssignSupporterForNextPendingSession(ISupporter supporter)
{
var owner = supporter.Owner;
if (!PendingSupportSessions.ContainsKey(owner)) //always returns false
{
var hashCode1 = owner.GetHashCode();
var hashCode2 = PendingSupportSessions.First().Key.GetHashCode();
var equals = owner.Equals(PendingSupportSessions.First().Key);
//here, equals is true, and the two hashcodes are identical,
//and there is only one element in the dictionary according to the debugger.
//however, calling two "Add" calls after eachother does indeed crash.
PendingSupportSessions.Add(owner, new LinkedList<IChatSession>());
PendingSupportSessions.Add(owner, new LinkedList<IChatSession>()); //crash
}
...
}
}
If you need additional information, let me know. I am not sure what kind of information would be sufficient, so it was hard for me to include more.
Guillaume was right. It appears that I was changing the value of one of my keys after it is added to the dictionary. Doh!
Make sure you are passing same object that is stored as key in dictionary. If you are creating new object each time and trying to find key assuming the object is already stored because of similar values, then containsKey returns false. Object comparisons are different than value comparisons.
Related
Please read my previous question, because my fear of getting collision when using hashCode for strings !
Previous question
I having a database table with items in a repo, and a "incoming" function with items from a model that should sync - to the database table.
Im using intersect and except to make this possible.
The class i use for my sunc purpose:
private class syncItemModel
{
public override int GetHashCode()
{
return this.ItemLookupCode.GetHashCode();
}
public override bool Equals(object other)
{
if (other is syncItemModel)
return ((syncItemModel)other).ItemLookupCode == this.ItemLookupCode;
return false;
}
public string Description { get; set; }
public string ItemLookupCode { get; set; }
public int ItemID { get; set; }
}
Then i use this in my method:
1) Convert datatable items to syncmodel:
var DbItemsInCampaignDiscount_SyncModel =
DbItemsInCampaignDiscount(dbcampaignDiscount, datacontext)
.Select(i => new syncItemModel { Description = i.Description,
ItemLookupCode = i.ItemLookupCode,
ItemID = i.ID}).ToList();
2) Convert my incoming item model to syncmodel:
var ItemsInCampaignDiscountModel_SyncModel = modelItems
.Select(i => new syncItemModel { Description =
i.Description, ItemLookupCode = i.ItemLookUpCode, ItemID =0 }).ToList();
3) Make an intersect:
var CommonItemInDbAndModel =
ItemsInCampaignDiscountModel_SyncModel.Intersect(DbItemsInCampaignDiscount_SyncModel).ToList();
4) Take out items to be deleted in database (that not exist in incoming model items)
var SyncModel_OnlyInDb =
DbItemsInCampaignDiscount_SyncModel.Except(CommonItemInDbAndModel).ToList();
5) Take out items to be added to database, items that exist in incoming model but not in db:
var SyncModel_OnlyInModel =
ItemsInCampaignDiscountModel_SyncModel.Except(CommonItemInDbAndModel).ToList();
My question is then - can it be a collision? Can two differnt ItemLookupCode in my example be treated as the same ItemLookupCode? Because intersect and except using HashCode ! Or vill the Equal function "double check" it -so this approach is safe to use? If its a possible chance of collision how big is that chance?
Yes, there could be always a hash-collision, that's why identity should be confirmed by calling Equals(). GetHashCode() and Equals() must be implemented correctly.
Except() in LINQ to Objects internally uses HashSet, in case of hash-collision it will call Equals to guarantee identity. As you are using a single property, you are good to proxy calls to its hashcode and equals methods.
Please find some comments below about your implementation:
comparison with ==
This is fine to compare strings with ==, but if type is changed to non-primitive, you'll get issues because object reference instead of content will be compared. Proxy call to Equals() instead of ==.
mutability of the object
That is very error prone to bound gethashcode/Equals logic to mutable state. I'd strongly recommend to encapsulate your state so that once you create your object it could not be changed, make set private for a sake of safety.
I think it is strange that the GetHashCode function of these collections don't base their hashcode on the items in their lists.
I need this to work in order to provide dirty checking (you have unsaved data).
I've written a wrapping class that overrides the GetHashCode method but I find it weird that this is not the default implementation.
I guess this is a performance optimization?
class Program
{
static void Main(string[] args)
{
var x = new ObservableCollection<test>();
int hash = x.GetHashCode();
x.Add(new test("name"));
int hash2 = x.GetHashCode();
var z = new List<test>();
int hash3 = z.GetHashCode();
z.Add(new test("tets"));
int hash4 = z.GetHashCode();
var my = new CustomObservableCollection<test>();
int hash5 = my.GetHashCode();
var test = new test("name");
my.Add(test);
int hash6 = my.GetHashCode();
test.Name = "name2";
int hash7 = my.GetHashCode();
}
}
public class test
{
public test(string name)
{
Name = name;
}
public string Name { get; set; }
public override bool Equals(object obj)
{
if (obj is test)
{
var o = (test) obj;
return o.Name == this.Name;
}
return base.Equals(obj);
}
public override int GetHashCode()
{
return Name.GetHashCode();
}
}
public class CustomObservableCollection<T> : ObservableCollection<T>
{
public override int GetHashCode()
{
int collectionHash = base.GetHashCode();
foreach (var item in Items)
{
var itemHash = item.GetHashCode();
if (int.MaxValue - itemHash > collectionHash)
{
collectionHash = collectionHash * -1;
}
collectionHash += itemHash;
}
return collectionHash;
}
}
If it did, it would break a few of the guidelines for implementing GetHashCode. Namely:
the integer returned by GetHashCode should never change
Since the content of a list can change, then so would its hash code.
the implementation of GetHashCode must be extremely fast
Depending on the size of the list, you could risk slowing down the calculation of its hash code.
Also, I do not believe you should be using an object's hashcode to check if data is dirty. The probability of collision is higher than you think.
The Equals/GetHashCode of lists checks for reference equality, not content equality. The reason behind this is, that lists are both mutable and by reference (not struct) objects. So every time you change the contents, the hash code would change.
The common use case of hash codes are hash tables (for example Dictionary<K,V> or HashSet), which sort their items based on hash when the are first inserted into the table. If the hash of an object wich is already in the table changes, it may no longer be found, wich leads to erratic behavior.
The key of GetHashCode is to reflect the Equals() logic, in a light weight way.
And List<T>.Equals() inherits Object.Equals(), and Object.Equals() compares the equality by reference, so that the list do not based on it's items, but the list itself
It would be helpful to have a couple types which behaved like List<T> and could generally be used interchangeably with it, but with GetHashCode and Equals methods which would define equivalence either in terms of the sequence of identities, or the Equals and GetHashCode behaviors of the items encapsulated therein. Making such methods to behave efficiently, however, would require that the class include code to cache its hash value but invalidate or update the cached hash value whenever the collection was modified (it would not be legitimate to modify a list while it was stored as a dictionary key, but it should be legitimate to remove a list, modify it, and re-add it, and it would be very desirable to avoid having such modification necessitate re-hashing the entire contents of the list). It was not considered worthwhile to have ordinary lists go through the effort of supporting such behavior at the cost of slowing down operations on lists that never get hashed; nor was it considered worthwhile to define multiple types of list, multiple types of dictionary, etc. based upon the kind of equivalence they should look for in their members or should expose to the outside world.
I have an object called Page, with an instance called p that has a custom property called AssociatedAttributes. If I do the following:
int numMatchingAttributes = p.AssociatedAttributes.Intersect( p.AssociatedAttributes ).Distinct( ).Count( );
numMatchingAttributes ends up equaling 0 even though p has 6 AssociatedAttributes. Why does it not equal 6?
AssociatedAttributes is of Type List<Attribute> (Attribute is my own class, not System.Attribute) and Attribute implements IComparable<Attribute>, I did not have it implement IEquatable, should I?
This is the implementation of CompareTo in Attribute:
public int CompareTo(Attribute other)
{
return Id.CompareTo(other.Id);
}
Id is of type Guid.
this is the AssociatedAttributes property on Page:
public List<Attribute> AssociatedAttributes
{
get
{
List<Attribute> list = new List<Attribute>( );
using (
PredictiveRecommendor dbContext =
new PredictiveRecommendor()){
if ( dbContext != null )
{
IQueryable<Attribute> query = from a in dbContext.PageAttributes
where a.Page.Id.Equals(this.Id)
select a.Attribute;
list = query.ToList();
}
}
return list;
}
}
(dbContext is a Telerik OpenAccess context)
Update: Here is what ended up working: In Page is the following method:
public int numberOfIntersectedAssociatedAttributes ( Page other )
{
using ( PredictiveRecommendor dbContext = new PredictiveRecommendor( ) )
{
IQueryable<Attribute> thisAssocAttributes = from a in dbContext.PageAttributes
where a.Page.Id.Equals( this.Id )
select a.Attribute;
IQueryable<Attribute> otherAssocAttributes = from a in dbContext.PageAttributes
where a.Page.Id.Equals( other.Id )
select a.Attribute;
IQueryable<Attribute> interSection = thisAssocAttributes.Intersect( otherAssocAttributes );
return interSection.ToList( ).Count;
}
}
It's ugly, but it works.
Consider the following implementation of Page:
public class Page
{
public List<Attribute> AssociatedAttributes
{
get
{
return new List<Attribute>() {
new Attribute { Value = "a" },
new Attribute { Value = "b" },
new Attribute { Value = "c" },
};
}
}
}
Here the AssociatedAttributes property is returning a different list each time AssociatedAttributes is called. Additionally, the actual items in the list are constructed each time the property is called, it's not just returning references to the same exact Attribute objects. Since Attribute (I assume) does not override Equals or GetHashCode, it will use the default object implementation, which considers objects equal if and only if they are referencing the same object. Since the objects in your two lists aren't referencing the same objects, none of them are equal to each other, even though they may have the same values internally.
The fact that Attribute implements IComparable is irrelivant.
There are several possible things that could be done to change the behavior:
Rather than constructing new objects in the property getter, return references to the same actual objects. This would likely mean having a private backing field for the property, constructing the objects once, and then returning references to the same list.
Override Equals and GetHashCode in Attribute to be dependent on its values, rather than its reference. Convention would dictate that you only do this if the object is immutable, as dealing with objects that have mutating GetHashCode values is...difficult. You could implement IEquatable in addition to doing this, if you wanted, to provide a statically typed Equals method. Note that it's vital to override GetHashCode if you implement IEquatable, if you still want it to be useful.
Create a new object that implements IEqualityComparer<Attribute>. This would be an object external to Attribute that knows how to compare them for equality based on something other than the Equals and GetHashCode implementation of the object itself. Provide an instance of such a type to Intersect and Distinct. (They each have overloads for custom equality comparers.)
I'm adding values to a c# generic list while trying to prevent duplicates, but without success. Anyone know of a reason why this code below wouldn't work?
I have a simple class here:
public class DrivePairs
{
public int Start { get; set; }
public int End { get; set; }
}
And here is my method which tries to return a generic list of the above class:
ArrayList found = DriveRepository.GetDriveArray(9, 138);
List<DrivePairs> drivePairs = new List<DrivePairs>();
foreach (List<int> item in found)
{
int count = item.Count;
if (count > 1)
{
for (int i = 0; i < (count - 1); i++)
{
DrivePairs drivePair = new DrivePairs();
drivePair.Start = item[i];
drivePair.End = item[i + 1];
if (!drivePairs.Contains(drivePair))
drivePairs.Add(drivePair);
}
}
}
drivePairs = drivePairs.Distinct().ToList();
As you can maybe see, I have an ArrayList, and each row contains a List<int>. What I'm doing is going through each and adding to a list which contains only pairs. E.g. if my List<int> contains [1,3,6,9] I want to add three entries to my pairs list:
[1,3]
[3,6]
[6,9]
It all works fine apart from not recognising duplicates. I thought this line would be enough:
if (!drivePairs.Contains(drivePair))
drivePairs.Add(drivePair);
but it continues to add them all. Even when I add a Distinct() at the end, it still doesn't remove them. I've also tried adding them to a HashSet, but it still includes all the duplicates.
Anyone know of a reason why the duplicates might not be getting picked up?
Your DrivePairs class does not specify equality, as a result, the Contains method will be using reference equality. Add an Equals method that uses both Start and End to determine equality and you will probably find your code works.
See: Equality Comparisons (C# Programming Guide)
List.Contains Method
This method determines equality by using the default equality
comparer, as defined by the object's implementation of the
IEquatable.Equals method for T (the type of values in the list).
Change your DrivePairs class
public class DrivePairs: IEquatable<DrivePairs>
{
public int Start { get; set; }
public int End { get; set; }
public bool Equals(DrivePairs other)
{
return (this.Start == other.Start && this.End == other.End)
}
}
See: http://msdn.microsoft.com/en-us/library/bhkz42b3.aspx
Hope this helps
You are creating new List<int> objects - these are different objects and when compared to each other, even if they contain identical values (in the same or in different orders), will be evaluated as different as the default comparison method on reference types is a reference comparison.
You need to write a custom comparer that will identify equal lists in the manner your application requires.
I've marked Colin's as the answer, but here was the code just in case it's any use to anyone:
Equality comparer:
public class EqualityComparer : IEqualityComparer<DrivePairs>
{
public bool Equals(DrivePairs x, DrivePairs y)
{
return x.StartHub.Equals(y.Start);
}
public int GetHashCode(DrivePairs obj)
{
return obj.Start.GetHashCode();
}
}
and in the controller:
IEqualityComparer<DrivePairs> customComparer = new EqualityComparer();
IEnumerable<DrivePairs> distinctDrivePairs = drivePairs.Distinct(customComparer);
drivePairs = distinctDrivePairs.ToList();
Thanks for all the help and comments
I have not tested it but I think the default equality test is if it is the same instance. Try overriding the Equals method and make it use your properties.
The DrivePairs class type is a reference type(remember reference type and value type concept). So when you check if DrivePairs varible is already added in List collections or not it return false as every DrivePairs varibale has different memory location from other.
Try using either Dictionary or StringDictionary or any other Key value pair collection. It will definately work.
I'm looking to use "phantom types" to implement type-safe identifiers. There's a question here about doing this in F#.
I'd like to do this in C#. How?
I've got a solution (which has problems), so I'll post it as a possible answer to see if anyone can improve it.
Why not make it a sealed class with its constructor private?
public sealed class Id<TDiscriminator>
{
private Id() { }
//some static methods
}
I've come up with the following:
struct Id<TDiscriminator>
{
private readonly Guid _id;
private Id(Guid id)
{
_id = id;
}
public Guid Value
{
get { return _id; }
}
public static Id<TDiscriminator> NewId()
{
return From(Guid.NewGuid());
}
public static Id<TDiscriminator> From(Guid id)
{
return new Id<TDiscriminator>(id);
}
public static readonly Id<TDiscriminator> Empty = From(Guid.Empty);
// Equality operators ellided...
}
...which I can use as follows:
class Order { /* empty */ }
class Customer { /* empty */ }
void Foo()
{
var orderId = Id<Order>.NewId();
var customerId = Id<Customer>.NewId();
// This doesn't compile. GOOD.
bool same = (orderId == customerId);
}
I don't particularly want concrete classes for the discriminator, because I don't want anyone instantiating them.
I could get around that by using an interface or an abstract class. Unfortunately, these can still be derived from and instantiated.
C# won't let you use a static class as a type argument. I can't say that I'm totally happy with the answers to that question, because the answers basically say "just because".
How about?
public sealed class Order
{
private Order() {}
}
public static sealed class Id<T>
{
// ...
}
I think that's exactly what you say. No one (except some special cases) can construct it and no one can inherit from it.
Well, as far as I could understand, you would like to provide a mechanism for distinguishing different types by a custom identifier object. I think you are almost near a working solution. In .NET when having a generic class, each substitution of the generic argument (or each unique combination of the generic arguments, if more than one) creates a unique type in the runtime. In your code Id<Order> and Id<Customer> are two distinct types. The NewId() method returns an instance of Id<Order> for the orderId and Id<Customer> for the customerId variables. The two types do not implement the == operator and therefore cannot be compared. Moreover, such comparison would be difficult to implement, since you cannot determine all possible uses of the Id<TDsicriminator> - you cannot guess what type will the TDsicriminator be substituted with.
1
A fast and simple solution will be to do this:
class Order { /* skipped */ }
class Customer { /* skipped */ }
void Foo()
{
var orderId = Id<Order>.NewId();
var customerId = Id<Customer>.NewId();
bool sameIds = (orderId.Value == customerId.Value); // true
bool sameObjects = orderId.Equals(customerId); // false
}
Since the Value properties are both of the Guid type, comparison is possible.
2
If you need however, to implement the == operator, or some sort of equality comparisons for instances of Id<TDisciminator>, the approach will be different. What comes up to my mind is the following:
public abstract class IdBase
{
public abstract Guid Value { get; protected set; }
public static bool operator == (IdBase left, IdBase right)
{
return left.Value == right.Value;
}
}
public sealed class Id<TDiscriminator> : IdBase
{
// your implementation here, just remember the override keyword for the Value property
}
Many people would not recommend the second approach though, since different implementations of IdBase may happen to have the same Value property (if you used the constructor that passes an existing ID). For instance:
var guid = Guid.NewGuid();
var customerID = Id<Customer>.From(guid);
var orderID = Id<Order>.From(guid);
Here (customerID == orderID) will then return true which is probably not what you want.
Shortly, in such a case, two different types will count as equal, which is a big logical mistake, so I'd stick to the first approach.
If you need Id<Customer>.Value to always be different than Id<Order>.Value, because of the different generic arguments (Customer is different than Order), then the following approach will work:
public sealed class Id<in TDiscriminator>
{
private static readonly Guid _idStatic = Guid.NewGuid();
private Id()
{
}
public Guid Value
{
get { return _idStatic; }
}
}
Notice the in keyword used here. This is applicable for .NET 4.0 where generics can be covariant and ensures that your class uses contravariant generics. (see http://msdn.microsoft.com/en-us/library/dd469487.aspx). In the above code, the _idStatic field will have a unique value for every different type supplied as a generic argument.
I hope this info is helpful.