Question

In a class public class ViewModelCollection<T> : ObservableCollection<T> where T : class
I have the method:

public T CurrentItem
{
    get { return defaultView.CurrentItem as T; }
    set
    {
        // ** wrong when T is of type string ** if (value != defaultView.CurrentItem)
        // ** wrong when T is of type string ** if (value != (T)defaultView.CurrentItem)
        if (!EqualityComparer<T>.Default.Equals(value, (T)defaultView.CurrentItem))
        {
            defaultView.MoveCurrentTo(value);
            OnPropertyChanged(new PropertyChangedEventArgs("CurrentItem"));
        }
        else return;
    }
}

I don't understand why the normal == operator behaves so that e.g. "New" != "New".
Probably been asked a thousand times but I still don't get it, it must have something to do with the use of generics?

Était-ce utile?

La solution

The following code:

if (value != (T)defaultView.CurrentItem)

Is resolved at compile-time, not runtime, to use object's != operator, which is simple reference comparison. It doesn't matter that T might overload/replace the meaning of !=, such as string's overloading to compare it via value instead of reference. Thus, it is not correct to compare generic types in such a way if you're expecting value comparison, and e.g. two strings with the value "New" might have new1 != new2 be true.

You could use your EqualityComparer<T>.Default code, which can make use of T's override of object.Equals(object), or you can use the static object.Equals(object, object), which also uses the type's overridden equality comparison. The only major difference here is that EqualityComparer<T>.Default will prefer to use the implementation provided by IEquatable<T>, if it exists.

if (!object.Equals(value, defaultView.CurrentItem))

Autres conseils

The == is an operator that can be overloaded by classes. Hence, the String class will overload this operator to return true, when both the Strings (even if they are different instances) are equal.

Object does not overload this Operator, means that == for Objects checks if its the same instance - which it is not.

Generics have no Type during compiletime, therefore the Operator will be Compiled as the Object's Operator rather than the String's Operator and will fail, even if the ACTUAL instances compared are of Type String.

String a = "Test";
String b = "Test";

MessageBox.Show((a == b).ToString()); 
//True, even if different instance: == compiled for string

Object c = new object();
Object d = new object();

MessageBox.Show((c == d).ToString()); 
//False, cause different instance: == compiled for object

See also this example:

This class will thread ALL Instances of Test equal, when comparing with == - because i said so! (Example just to show that the operator definition ALWAYS depends on the types compared and how they implement the operator)

 private class Test{

        private string s;

        public Test(string s)
        {
            this.s = s;
        }

        public static Boolean operator ==(Test c1, Test c2)
        {
            return true;
        }

        public static Boolean operator !=(Test c1, Test c2)
        {
            return false;
        }
    }

    Test x = new Test("Hello");
    Test y = new Test("World");

     MessageBox.Show((x == y).ToString()); // True
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top