I have a property in a composite control that checks to see if the value has changed prior to actually setting the related private field and doing a few other things.
However, it appears that it is never evaluating the statement.
Here is the code for the property:
public T SearchCriteria
{
get
{
return mySearchCriteria;
}
set
{
if (value != mySearchCriteria)
{
mySearchCriteria = value;
EnsureChildControls();
SearchGridParser parser = SearchGridParserFactory.GetParser(this.Type);
parser.SetSearchPanelControls<T>(this.mySearchCriteria, ref mySearchParametersPanel);
GridView.PageIndex = 0;
}
}
}
I have stepped through the code, and everytime it gets to "value != mySearchCriteria" it evaluates to false and skips the code inside the if statement. In fact, it does this even when I change it to "value == mySearchCriteria".. if just completely skips it no matter how it evaluates!
What the hey?
I've tried changing the order of the arguments in the check, and also using object.Equals() but none of these changes have made any difference.
I have overridden Equals, !=, == and GetHashCode.
There are other places in the code where it uses the "==" and "!=" for these object types without a problem, so I know that my overriding is working correctly.
Problem is, this never even hits the overriden methods. I put breaks on "==", "!=", "Equals" and "GetHashCode" and none of them are being called when the "value != mySearchCriteria" statement is being evaluated.
It's like it completely skips evaluating it.
Using == between generic types is almost always a bad idea. Operators are overloaded rather than overridden, so even if there is an == operator on your actual types, the compiler won't know about it. (That means your claim that you've "overridden" == and != is already incorrect - you've overloaded those operators. You should make sure you understand the difference, as it's very important.)
When you write:
There are other places in the code where it uses the "==" and "!=" for these object types without a problem, so I know that my overriding is working correctly.
I suspect those areas aren't in generic code... they're where the compiler knows what types are being compared, so knows to use your overloads. That's very different from your generic situation, where the compiler doesn't know what to use for ==, so falls back to reference identity.
I assume you have a generic constraint of where T : class or your code wouldn't compile at all - but it's still just going to perform a reference comparison, instead of using whatever overload is provided by the actual type of T.
Use EqualityComparer.Default<T>.Equals(value, mySearchCriteria) to use overridden implementations of Equals including IEquatable<T>.
Related
I was looking for the difference between == and .Equals methods in C# and I found that the first one compares the object references, and the second one compares the objects values, except for the string datatypes both == and .Equals() does a content comparison. I can't really find an explanation for that, is it because the string datatypes are immutable ?
Here's what I want to say
object obj1 = "Test";
object obj2 = new string("Test".ToCharArray());
Console.WriteLine(obj1.Equals(obj2) + " " + (obj1 == obj2));
string a = "Test";
string b = "Test";
Console.WriteLine(a.Equals(b) + " "+ (a == b));
Output
True False
True True
In fact for the first comparison we have two different objects with same value and we got as result True and false, but for the case of string we have true for both comparison
This isn't true at all. == is an overridable operator, and Equals is an overridable method. It's up to the class to define how each of them behaves.
Perhaps you're confusing C# with Java?
If you want to do a reference comparison, use object.ReferenceEquals. Everything else is implementation dependant (though note that operator overrides are checked statically, so e.g. (object)someString == (object)someOtherString will do a reference comparison, not a value comparison; Equals doesn't have this "problem").
Most often, both == and Equals are designed to give the same answer (though == is always stricter about types in the comparison, as mentioned before). This applies double for structs, where a reference comparison doesn't really make much of a sense anyway.
And of course, the compiler doesn't actually do any checks. If I want, I can override the == operator to always return false. Or to only check some ID for equality. Or to change the objects being compared, if you are feeling particularly evil. In the end, it's just a static method like any other (with a few restrictions).
EDIT:
To address your edit directly, string always performs a content comparison because both its == and Equals are overriden to perform a content comparison. However, that doesn't mean that it always performs a costly char-by-char comparison - if you look how string.Equals is actually implemented, you can see that it tries a few things to avoid the costly comparison:
If the string is null, they must be different
If the two strings are reference-equal, they must also be content-equal
If the two strings don't have the same length, they must be different
You can see the actual by-value comparison method here - http://referencesource.microsoft.com/#mscorlib/system/string.cs,11648d2d83718c5e A simple piece of unsafe code, but manually written code nevertheless. There's no automatic value comparison in .NET (though there's tricks that come close).
It's because it makes sense.
Java couldn't do it this way because it doesn't have operator overloading, but that's no argument in C#.
This isn't unique to strings, by the way. Any type could overload the == operator to do something similar.
Any object can override/overload Equals or ==, so they can behave however the library author wants them to behave.
The following extension method tries, for a given value of unknown type, to find a constructor with a single parameter such that the constructor can be called with that value.
private static ConstructorInfo ConstructorThatTakesValue
(this Type thisType, object value)
{
return thisType.GetConstructors().FirstOrDefault(c =>
c.GetParameters().Count() == 1 &&
c.GetParameters().First().ParameterType.IsAssignableFrom(value.GetType()));
}
That is, if var c = typeof(X).ConstructorThatTakesValue(y), then we can create a x by
var x = (X)c.Invoke(new object[] { y });
The code above works like a charm, but Resharper marks the line containing IsAssignableFrom and displays "Use method InstanceOfType". It also provides a QuickFix which literally just replaces IsAssignableFrom by IsInstanceOfType, which by my intuition is the exact opposite of what I am trying to achieve:
c.GetParameters().First().ParameterType.IsInstanceOfType(value.GetType()));
Even more suspicious, this message is displayed as a "suggestion", not a warning or so. That is, Resharper seems to consider the change a simple stylistic improvement.
I also tried to gain understanding of the semantics of the two methods, but I was not able to grasp the meaning of documentation on the MSDN either. My understanding would be that if class A : B, then B.GetType().IsAssignableFrom(A.GetType()) and A.GetType().IsInstanceOfType(B.GetType()).
One works with Types and the Other instances, in fact one calls the other:
public virtual bool IsInstanceOfType(object o)
{
if (o == null)
{
return false;
}
return this.IsAssignableFrom(o.GetType());
}
Kevin Cooks answer is good, but there is an overlook in Resharper's engine: it does not differenciate from Objects and Types (it treat the Type instance as an Object).
As in, if your B argument is already a Type object, it will still ask you to switch to "IsInstanceOf". Which is false and will lead to errors in this very limited context.
EDIT: I double check my test case I founf out it's not longer the case. When the second argument type is indeed Type, it correctly uses the IsAssignableFrom method without warnings.
In my program, I have objects derived from Dictionary. I need to check if 2 objects are equal, so I made an overload operator ==.
But at a later point, I need to check if a object is null.
If (object == null)
{...}
So at this point, the program goes into the overload operation I have defined, but will throw a NullReferenceException, since one of the objects to compare is null.
So within the overload operation, I need to check if one object is null, but without using ==, since that would give me a StackOverflowException.
How can I check this?
In my program, I have objects derived from Dictionary.
I would strongly reconsider deriving from Dictionary in the first place. That's very rarely a good idea. Favour composition over inheritance in general, and think very carefully about how you want equality (and hash codes) to behave in the face of mutable data. It's usually a bad sign if two objects are equal at one point and then not equal later.
So at this point, the program goes into the overload operation I have defined, but will throw a NullReferenceException, since one of the objects to compare is null.
That's the problem. Your overloaded == operator should not throw an exception - it should compare the value with null.
Typically an overload of == looks something like this:
public static bool ==(Foo left, Foo right)
{
if (ReferenceEquals(left, right))
{
return true;
}
if (ReferenceEquals(left, null))
{
return false;
}
// Equals should be overridden, and should be handling the case where
// right is null (by checking with ReferenceEquals too). Also consider
// implementing IEquatable<Foo>
return left.Equals(right);
}
Here Object.ReferenceEquals is used to perform the reference identity comparison. You could use this outside (in the code that you're currently considering changing) but it would be cleaner just to make == behave correctly.
You either need to cast to object,
(object)obj == null
or use object.ReferenceEquals(obj, null);
(object is not a nice name for an object)
You have to check for null in your implementation of overriden ==, following these guidelines for example :
http://msdn.microsoft.com/en-us/library/ms173147%28v=vs.80%29.aspx
You could also use
object.ReferenceEquals(myInstance, null);
Please note that overriding base operators such as == and/or directly overriding .Net base types such as Dictionary are both not very good practices.
overriding the == operator, as you have discovered, has non-obvious side effects and generally should be avoided.
You might consider having your object implement IComparable instead, and then calling CompareTo instead of ==.
use the is null operator from c# 7
if(object is null)...
Today I stumbled upon an interesting bug I wrote. I have a set of properties which can be set through a general setter. These properties can be value types or reference types.
public void SetValue( TEnum property, object value )
{
if ( _properties[ property ] != value )
{
// Only come here when the new value is different.
}
}
When writing a unit test for this method I found out the condition is always true for value types. It didn't take me long to figure out this is due to boxing/unboxing. It didn't take me long either to adjust the code to the following:
public void SetValue( TEnum property, object value )
{
if ( !_properties[ property ].Equals( value ) )
{
// Only come here when the new value is different.
}
}
The thing is I'm not entirely satisfied with this solution. I'd like to keep a simple reference comparison, unless the value is boxed.
The current solution I am thinking of is only calling Equals() for boxed values. Doing a check for a boxed values seems a bit overkill. Isn't there an easier way?
If you need different behaviour when you're dealing with a value-type then you're obviously going to need to perform some kind of test. You don't need an explicit check for boxed value-types, since all value-types will be boxed** due to the parameter being typed as object.
This code should meet your stated criteria: If value is a (boxed) value-type then call the polymorphic Equals method, otherwise use == to test for reference equality.
public void SetValue(TEnum property, object value)
{
bool equal = ((value != null) && value.GetType().IsValueType)
? value.Equals(_properties[property])
: (value == _properties[property]);
if (!equal)
{
// Only come here when the new value is different.
}
}
( ** And, yes, I know that Nullable<T> is a value-type with its own special rules relating to boxing and unboxing, but that's pretty much irrelevant here.)
Equals() is generally the preferred approach.
The default implementation of .Equals() does a simple reference comparison for reference types, so in most cases that's what you'll be getting. Equals() might have been overridden to provide some other behavior, but if someone has overridden .Equals() in a class it's because they want to change the equality semantics for that type, and it's better to let that happen if you don't have a compelling reason not to. Bypassing it by using == can lead to confusion when your class sees two things as different when every other class agrees that they're the same.
Since the input parameter's type is object, you will always get a boxed value inside the method's context.
I think your only chance is to change the method's signature and to write different overloads.
How about this:
if(object.ReferenceEquals(first, second)) { return; }
if(first.Equals(second)) { return; }
// they must differ, right?
Update
I realized this doesn't work as expected for a certain case:
For value types, ReferenceEquals returns false so we fall back to Equals, which behaves as expected.
For reference types where ReferenceEquals returns true, we consider them "same" as expected.
For reference types where ReferenceEquals returns false and Equals returns false, we consider them "different" as expected.
For reference types where ReferenceEquals returns false and Equals returns true, we consider them "same" even though we want "different"
So the lesson is "don't get clever"
I suppose
I'd like to keep a simple reference comparison, unless the value is boxed.
is somewhat equivalent to
If the value is boxed, I'll do a non-"simple reference comparison".
This means the first thing you'll need to do is to check whether the value is boxed or not.
If there exists a method to check whether an object is a boxed value type or not, it should be at least as complex as that "overkill" method you provided the link to unless that is not the simplest way. Nonetheless, there should be a "simplest way" to determine if an object is a boxed value type or not. It's unlikely that this "simplest way" is simpler than simply using the object Equals() method, but I've bookmarked this question to find out just in case.
(not sure if I was logical)
Why does the C# compiler not even complain with a warning on this code? :
if (this == null)
{
// ...
}
Obviously the condition will never be satisfied..
Because you could override operator == to return true for that case.
public class Foo
{
public void Test()
{
Console.WriteLine(this == null);
}
public static bool operator ==(Foo a, Foo b)
{
return true;
}
public static bool operator !=(Foo a, Foo b)
{
return true;
}
}
Running new Foo().Test() will print "True" to the console.
The other question here is: why doesn't the compiler issue a warning for ReferenceEquals(this, null)? From the bottom of the above link:
A common error in overloads of operator == is to use (a == b), (a == null), or (b == null) to check for reference equality. This instead results in a call to the overloaded operator ==, causing an infinite loop. Use ReferenceEquals or cast the type to Object, to avoid the loop.
That might be answered by #Aaronaught's response. And that's also why you should be doing (object)x == null or ReferenceEquals(x, null), not doing a simple x == null, when you're checking for null references. Unless, of course, you're sure that the == operator is not overloaded.
Wow... I guess I was shamefully wrong
I disagree. I think you still make a good point.
The compiler knows whether the comparison is going to go to a user-defined comparison operator or not, and the compiler knows that if it does not, then 'this' is never null.
And in fact, the compiler does track whether a given expression can legally be null or not, in order to implement a minor optimization on non-virtual method calls. If you have a non-virtual method M and you say foo.M(); then the compiler generates this as "do a virtual call to M with receiver foo". Why? Because we want to throw if foo is null, and a virtual call always does a null check on the receiver. A non-virtual call does not; we'd have to generate it as "check foo for null, and then do a non-virtual call to M", which is longer, slower, more irritating code.
Now, if we can get away without doing the null check, we do. If you say this.M() or (new Foo()).M() then we do NOT generate a virtual call. We generate the non-virtual call without the null check because we know that it cannot be null.
So the compiler has excellent data on whether a particular comparison to null will sometimes, always, or never succeed.
The question then is "if the compiler knows that a particular comparison will never succeed, why not generate a warning for it?"
And the answer is "sometimes we do, and sometimes we don't".
We do in this situation:
int x = 123;
if (x == null) ...
There is an equality operator defined on two nullable ints. x is convertible to nullable int. null is convertible to nullable int. So that equality operator is valid, and therefore is used, and is of course always false. The compiler gives a warning that the expression is always false.
However, due to a bug we accidentally introduced in C# 3, this code does NOT produce that warning:
Guid x = whatever;
if (x == null) ...
Same deal. The nullable guid equality operator is valid, but the warning is suppressed. I'm not sure if we fixed this bug for C# 4 or not. If not, hopefully we'll get it into a service pack.
As for "if (this == null)" I don't know why we don't warn for that. It certainly seems like a good candidate for a warning. The most likely explanation is to follow this logical syllogism:
warnings are compiler features
compiler features must be (1) thought of, (2) designed, (3) implemented, (4) tested, (5) documented and (6) shipped to you before you can take advantage of the feature.
No one has done any of those six necessary things for this feature; we can't ship features that we never thought of in the first place.
therefore, no such feature.
There are infinitely many compiler features that we haven't thought of yet; we've implemented none of them.
Another reason to not give a warning here is that we try to give warnings on code which is both likely to be typed by accident and almost certainly wrong for a non-obvious reason. "this == null" is not likely to be typed in by accident, and though it is almost certainly wrong, as you note in the statement of your question, it is obviously wrong.
Compare that to our "guid == null" -- that is likely to happen by accident, because a developer might accidentally think that Guid is a reference type. Guids are usually passed around by reference in C++, so this is an easy mistake to make. The code is almost certainly wrong, but it is wrong in a non-obvious way. So this is a good candidate for a warning. (Which is why it is so unfortunate that this is a warning in C# 2 but not C# 3, due to a bug we introduced.)
Actually, the condition really can be satisfied, at least in Visual Studio 2008. They've fixed this behaviour in VS 2010, but it is not totally inconceivable that there might be another way to create such a condition.
(tl;dr version - in C# 3.5, it's legal to reference this from an anonymous function passed as a constructor argument, but if you actually try to use it, you'll find that this is null.)
Though the code below is a bastard it's still all C#. an if you call Bar you will get an InvalidOperationException with the message null.
public class Foo
{
static Action squareIt;
static Foo() {
var method = new DynamicMethod(
"TryItForReal",
typeof(void),
Type.EmptyTypes,
typeof(Foo).Module);
ILGenerator il = method.GetILGenerator();
il.Emit(OpCodes.Ldnull);
il.Emit(OpCodes.Call, typeof(Foo).GetMethod("tryit"));
il.Emit(OpCodes.Ret);
squareIt = (Action)method.CreateDelegate(typeof(Action));
}
public void tryit()
{
if (this == null) {
throw new InvalidOperationException("Was null");
}
}
public void Bar() {
squareIt();
}
}
This also falls in line with other warnings C# does (or not does for that matter) like:
if(true)
or
if(1 == 1)
These will also always have the same result no matter what.