views:

120

answers:

6

Any ideas as to why this

    public Collection<Point> data = new Collection<Point>(){
            new Point{X=10,Y=20},
            new Point{X=20,Y=30},
            new Point{X=40,Y=20},
            new Point{X=10,Y=20}
           };

(notice the identical first and last elements) gives the error

An item with the same key has already been added.

If you change the last element to Y=20.1 or anything that makes it different then it works. Also you can add the elements anyway you like and get the same result.

The problem is obviously due to Point being a value type because it goes away if you define and use a point class and I know that there are problems with using structs in other collection types but this has to do with the difference between value and ref return types. What mystifies me is that this works if the all the structs have different field values.

A: 

I'm really not sure on this, but I have a feeling that because the compiler generates a strong Collections item that doesn't require to box/unbox value types, the key check is done on the explicit value type itself, which produces the duplicate key exception?

That's really just a shot in the dark!

Matthew Abbott
Random downvote with no comments?
Matthew Abbott
+2  A: 

Have you tried using a List instead? I think it should work!

Hope that helps!

Kieren Johnstone
A: 

What is Collection class. It's not .NET Framework library class. Look docs or sources of this class, it would explain the proublem.

MaxFX
@Graham: But that 1 allows dupes.
Henk Holterman
Well, `Collection` *is* a Framework class (http://msdn.microsoft.com/en-us/library/ms132397(d=lightweight).aspx), but it doesn't care if duplicate items are added.
Graham Clark
Sorry, I've forgot about ObjectModel namespace. But the code works correct on my PC with all frameworks versions in any rate.
MaxFX
+5  A: 

The reason is because equality of a value type is based on its values - for struct it is equality across all its fields.

Reference type equality is based on the reference itself and thus works. Changing the struct values to be all different also works.

If you just want a list of stuff, just use List<Point>, I think that will accept duplicates.

Update: it looks like your collection class is detecting duplicate entries and you are trying to add duplicates. If you want to add duplicates, I would say you cannot use this class.

Adam
this is all very interesting but the code sample from question works fine as it is.
Andrey
Doesn't matter if his sample code compiles - it might not be exhaustive. The fact remains he gets his exception because it's detecting equality on the struct - and the OP doesn't seem to understand struct usage.
Adam
@Downvoter why?
Adam
See my comments on the question for a further discussion.
Adam
You are a rockstar. Catch my vote.
aloneguid
This is the best answer - yes its value v reference types but I am still surprised by the behaviour scince the documentation says"and allows duplicate elements".Clearly the implementor was trying to filter out durpicate references to the same object not different objects with identical values (i.e. equality of reference) but ended up excluding two distinct value types that just happen to have the same values.I'd say that this was a bug rather than a feature...
mikej
Good answer! +1!!
jameschinnock
+1  A: 

I'm not familiar with this collection class you're using but apparently it doesn't allow multiple items to be in it. As it is with a SET collection. So I guess the Collection you're using is equivalent to:

Dictionary<String, Point>

but since you you dont have a key it's more like

HashSet<Point>

Just like your collection class a HashSet requires all keys to be unique. Like Kieren mentions a List would be more suitable for you. A list allows multiple entries to be the same.

Indeed if Point was a class it would allow duplicates since Objec1 != Object2 to even if their values are the same.

Sjuul Janssen
For your second code block, replace "`Dictionary<Point>` //Note this isn't possible" with `HashSet<Point>`.
Joe White
Thanks, I've updated it
Sjuul Janssen
+1  A: 

I will assume that you were talking about some MyCollection<Point> where MyCollection does not allow duplicates. In that case, your question can be simplified to:

   public struct PointS
    {
        public int X, Y;
    }

    public class PointC
    {
        public int X, Y;
    }

    static void Main(string[] args)
    {

        PointS ps1 = new PointS() { X = 10, Y = 20 };
        PointS ps2 = new PointS() { X = 10, Y = 20 };

        PointC pc1 = new PointC() { X = 10, Y = 20 };
        PointC pc2 = new PointC() { X = 10, Y = 20 };

        Console.WriteLine(ps1.Equals(ps2));
        Console.WriteLine(pc1.Equals(pc2));
    }

which prints

True
False

Equality of structures is by Value, but classes default to Equality based on Reference, which means Equals() only looks at the memory location (== identity) of an object.

You can overload Equals for a class to let it compare by value. The System.String class does this.

You cannot overload Equals for a structure so that it compares by reference.

Henk Holterman