After seeing a similar question, I was wondering if the following expression ...
if (attribute != null && attribute.Description == input)
... would behave (almost) identical, to following null-propagation variant?
if (attribute?.Description == input)
So far, I could determine only following (somehow minor) differences:
not possible in case input is of non-nullable type
in case input would be itself null, behavior would be altered
Am I missing something? or are there other differences in behavior?
EDIT: in the end, the only fail-safe alternative I've found for the first snippet, would be:
if (attribute?.Description?.Equals(input) ?? false)
The code will work if input is of a non-nullable type. There is an implicit conversion of all non-nullable types to their nullable counterparts, so input will simply be lifted to a nullable to be compared to the property value.
The only difference in behavior, as you mentioned is that, if input is null, then the second snippet has no way of differentiating between attribute being null, when it should be false, and where Description is null, where it should be true.
Oh, and this is assuming that attribute is a local variable or field. If it's a property (or is actually a more complex expression) then it could have side effects or result in a different value when computed twice, as happens in the first snippet but not the second, which is a difference in behavior.
This is all of course assuming a single threaded context. In a multithreaded context, if attribute is accessible from another thread (either because it's a field that's accessible or because it's closed over in a lambda that is exposed to another thread) then the value could be different each time it's computed, so the two snippets differ for the same reason described in the previous paragraph.
Related
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)
I am trying to figure out how to do an Equal on the following code:
Int32? testValue = 264;
MyTable.Where(a=>a.MyNullableNumberField.Equals(testValue));
I am stuck with the nullable field and I have to make the Equals method work. I know that I could use "==" and it would work but in this case I have to use the Equals method.
The error that I get returned is:
Unable to create a constant value of type 'System.Object'. Only primitive types or enumeration types are supported in this context.
You have to realize the difference between the == operator and .Equals(). Generally, the == operator compares references, while .Equals() is used to compare values. Of course, a comparison in the latter sense will only work with primitive types out of the box. Any object more complex than that (e.g. a user defined class) will need to have a custom .Equals() defined for it, to specify what exactly makes two instances of that object equal.
Normally, C# is smart enough to take care of things on its own when it comes to nullable numbers. However in certain cases (such as linq-to-entities) you have to push it in the right direction. This should work:
a.MyNullableNumberField.Value.Equals(testValue)
And to be totally safe, add a check right before to make sure the value exists:
a.MyNullableNumberField.HasValue && a.MyNullableNumberField.Value.Equals(testValue)
Could someone please be kind enough to explain why calling ToString() on an empty reference type causes an exception (which in my mind makes perfect sense, you cant invoke a method on nothing!) but calling ToString() on an empty Nullable(Of T) returns String.Empty? This was quite a surprise to me as I assumed the behaviour would be consistent across types.
Nullable<Guid> value = null;
Stock stock = null;
string result = value.ToString(); //Returns empty string
string result1 = stock.ToString(); //Causes a NullReferenceException
Nullable<T> is actually a struct that has some compiler support and implementation support to behave like a null without actually being null.
What you are seeing is the collision between the implementation allowing you to treat it naturally as a null as you would any other reference type, but allowing the method call to happen because the Nullable<T> isn't actually null, the value inside it is null.
Visually it looks like it shouldn't work, this is simply because you cannot see what is done in the background for you.
Other such visual trickery can be seen when you call an extension method on a null reference type... the call works (against visual expectation) because under the hood it is resolved into a static method call passing your null instance as a parameter.
How does a Nullable<T> type work behind the scenes?
Nullable is a value type and the assignment to null causes it to be initialized with Value=null and HasValue=false.
Further, Nullable.ToString() is implement as follows:
public override string ToString()
{
if (!this.HasValue)
{
return "";
}
return this.value.ToString();
}
So what you are seeing is expected.
It is a bit tricky with nullable types. When you set it to null it is actualy not null cause it is not reference type (it is value type). When you initialize such variable with null it creates new sctructure instance where HasValue property is false and it's Value is null, so when you call ToString method it works well on structure instance.
The exception raised by calling default(object).ToString() is called NullReferenceException for a reason, it's calling a method on a null reference. default(int?) on the other hand, is not a null reference, because it's not a reference; it is a value type with a value that is equivalent to null.
The big practical point, is that if this was done, then the following would fail:
default(int?).HasValue // should return false, or throw an exception?
It would also screw-up the way we have some ability to mix nullables and non-nullables:
((int?)null).Equals(1) // should return false, or throw an exception?
And the following becomes completely useless:
default(int?).GetValueOrDefault(-1);
We could get rid of HasValue and force comparison with null, but then what if the equality override of the value-type that is made nullable can return true when compared to null in some cases. That may not be a great idea, but it can be done and the language has to cope.
Let's think back to why nullable types are introduced. The possibility that a reference type can be null, is inherent in the concept of reference types unless effort is taken to enforce non-nullability: Reference types are types that refer to something, and that implies the possibility of one not referring to anything, which we call null.
While a nuisance in many cases, we can make use of this in a variety of cases, such as representing "unknown value", "no valid value" and so on (we can use it for what null means in databases, for example).
At this point, we've given null a meaning in a given context, beyond the simple fact that a given reference doesn't refer to any object.
Since this is useful, we could therefore want to set an int or DateTime to null, but we can't because they aren't types that refer to something else, and hence can't be in a state of not referring to anything any more than I as a mammal can lose my feathers.
The nullable types introduced with 2.0 give us a form of value types that can have the semantic null, through a different mechanism than that of reference types. Most of this you could code yourself if it didn't exist, but special boxing and promotion rules allow for more sensible boxing and operator use.
Okay. Now let's consider why NullReferenceExceptions happen in the first place. Two are inevitable, and one was a design decision in C# (and doesn't apply to all of .NET).
You try to call a virtual method or property, or access a field on a null reference. This has to fail, because there's no way to look up what override should be called, and no such field.
You call a non-virtual method or property on a null reference which in turn calls a virtual method or property, or accesses a field. This is obviously a variant on point one, but the design decision we're coming to next has the advantage of guaranteeing this fails at the start, rather than part-way through (which could be confusing and have long-term side-effects).
You call a non-virtual method or property on a null reference which does not call a virtual method or property, or access a field. There's no inherent reason why this should not be allowed, and some languages allow it, but in C# they decided to use callvirt rather than call to force a NullReferenceException for the sake of consistency (can't say I agree, but there you go).
None of these cases apply in any way to a nullable value type. It is impossible to put a nullable value type into a condition in which there is no way to know which field or method override to access. The whole concept of NullReferenceException just doesn't make sense here.
In all, not throwing a NullReferenceException is consistent with the other types - types through it if and only if a null reference is used.
Note that there is a case where calling on a null nullable-type throws, it does so with GetType(), because GetType() is not virtual, and when called on a value-type there is always an implied boxing. This is true of other value types so:
(1).GetType()
is treated as:
((object)1).GetType()
But in the case of nullable types, boxing turns those with a false HasValue into null, and hence:
default(int?).GetType()
being treated as:
((object)default(int?)).GetType()
which results in GetType() being called on a null object, and hence throwing.
This incidentally brings us to why not faking NullReferenceType was the more sensible design decision - people who need that behaviour can always box. If you want it to through then use ((object)myNullableValue).GetString() so there's no need for the language to treat it as a special case to force the exception.
EDIT
Oh, I forgot to mention the mechanics behind NullReferenceException.
The test for NullReferenceException is very cheap, because it mostly just ignores the problem, and then catches the exception from the OS if it happens. In other words, there is no test.
See What is the CLR implementation behind raising/generating a null reference exception? and note how none of that would work with nullable value types.
If you investigate Nullable<> definition, there is an override ToString definition. In this function, ToString is overriden to return String.Empty.
// Summary:
// Returns the text representation of the value of the current System.Nullable<T>
// object.
//
// Returns:
// The text representation of the value of the current System.Nullable<T> object
// if the System.Nullable<T>.HasValue property is true, or an empty string ("")
// if the System.Nullable<T>.HasValue property is false.
public override string ToString();
On the otherhand, Stock is a custom class, which I assume ToString is not overriden. Thus it returns NullReferenceException since it uses default behaviour.
As per MSDN Remarks
Guid.ToSTring() method Returns a string representation of the
value of this Guid instance, according to the provided format
specifier.
As per MSDN Remarks on Nullable
A type is said to be nullable if it can be assigned a value or can be
assigned null, which means the type has no value whatsoever.
Consequently, a nullable type can express a value, or that no value
exists. For example, a reference type such as String is nullable,
whereas a value type such as Int32 is not. A value type cannot be
nullable because it has enough capacity to express only the values
appropriate for that type; it does not have the additional capacity
required to express a value of null.
I tend to do this, for example a method that accepts an integer:
DoSomethingWithThisInt((int)dbObj.nullableInteger);
However I will also usually ensure that this code will never happen unless it has a value, sometimes this means I have to check for null first which takes more lines of code.
Is there a better way or am I doing this right by simply casting?
If you've already checked for null prior to the line of code in question, you can simply use
dbObj.nullableInteger.Value
As opposed to a cast.
If, for example, default values would also be sufficient (such as 0 for integers, false for booleans, etc.), then you can omit the null check and simply utilize
doObj.nullableInteger.GetValueOrDefault()
Basically there are two choices for syntax. Either use the properties of the Nullable<T> type, like so:
if (dbObj.nullableInteger.HasValue)
{
DoSomethingWithThisInt(dbObj.nullableInteger.Value);
}
or use the syntactic sugar provided by the C# language, which translates to the same thing:
if (dbObj.nullableInteger != null)
{
DoSomethingWithThisInt((int)dbObj.nullableInteger);
}
Which one you use is just a matter of preference; personally I prefer the latter.
I've been searching for some good guidance on this since the concept was introduced in .net 2.0.
Why would I ever want to use non-nullable data types in c#? (A better question is why wouldn't I choose nullable types by default, and only use non-nullable types when that explicitly makes sense.)
Is there a 'significant' performance hit to choosing a nullable data type over its non-nullable peer?
I much prefer to check my values against null instead of Guid.empty, string.empty, DateTime.MinValue,<= 0, etc, and to work with nullable types in general. And the only reason I don't choose nullable types more often is the itchy feeling in the back of my head that makes me feel like it's more than backwards compatibility that forces that extra '?' character to explicitly allow a null value.
Is there anybody out there that always (most always) chooses nullable types rather than non-nullable types?
Thanks for your time,
The reason why you shouldn't always use nullable types is that sometimes you're able to guarantee that a value will be initialized. And you should try to design your code so that this is the case as often as possible. If there is no way a value can possibly be uninitialized, then there is no reason why null should be a legal value for it. As a very simple example, consider this:
List<int> list = new List<int>()
int c = list.Count;
This is always valid. There is no possible way in which c could be uninitialized. If it was turned into an int?, you would effectively be telling readers of the code "this value might be null. Make sure to check before you use it". But we know that this can never happen, so why not expose this guarantee in the code?
You are absolutely right in cases where a value is optional. If we have a function that may or may not return a string, then return null. Don't return string.Empty(). Don't return "magic values".
But not all values are optional. And making everything optional makes the rest of your code far more complicated (it adds another code path that has to be handled).
If you can specifically guarantee that this value will always be valid, then why throw away this information? That's what you do by making it a nullable type. Now the value may or may not exist, and anyone using the value will have to handle both cases. But you know that only one of these cases is possible in the first place. So do users of your code a favor, and reflect this fact in your code. Any users of your code can then rely on the value being valid, and they only have to handle a single case rather than two.
Because it's inconvenient to always have to check whether the nullable type is null.
Obviously there are situations where a value is genuinely optional, and in those cases it makes sense to use a nullable type rather than magic numbers etc, but where possible I would try to avoid them.
// nice and simple, this will always work
int a = myInt;
// compiler won't let you do this
int b = myNullableInt;
// compiler allows these, but causes runtime error if myNullableInt is null
int c = (int)myNullableInt;
int d = myNullableInt.Value;
// instead you need to do something like these, cumbersome and less readable
int e = myNullableInt ?? defaultValue;
int f = myNullableInt.HasValue ? myNullableInt : GetValueFromSomewhere();
I think the language designers feel that 'reference types being nullable by default' was a mistake, and that non-nullable is the only sensible default, and you should have to opt into nullness. (This is how it is in many modern functional languages.) "null" is usually a heap of trouble.
You seem to have 2 different questions...
Why would I ever want to use non-nullable data types in C#?
Simple, because the value-type data you're relying on is guaranteed by the compiler to actually have a value!
Why wouldn't I choose nullable types by default, and only use non-nullable types when that explicitly makes sense?
As Joel has already mentioned, a type can only be null if it is a reference type. Value types are guaranteed by the compiler to have a value. If your program depends on a variable to have a value, then this is the behavior you will want by not choosing a nullable type.
Of course, when your data is coming from anywhere that is not your program, then all bets are off. The best example is from a database. Database fields can be null, so you would want your program variable to mimic this value - not just create a "magic" value (i.e. -1, 0, or whatever) that "represents" null. You do this with nullable types.
Although null values can be convenient for using as "not-initialized-yet" or "not-specified" values, they make the code more complex, mainly because you're overloading the meaning of null as well as the variable (number-or-null vs. just-a-number).
NULL values are favoured by many database designers and SQL database programmers but with a small change in thinking about the problem you can do away with null values and actually have simpler and more reliable code (e.g., no worrying about NullReferenceExceptions).
There's actually a large demand for a "T!" operator that makes any reference type non-nullable, similar to how "T?" makes value types nullable, and Anders Hejlsberg, the inventor of C#, wished he had included the ability.
See also the question, Why is “null” present in C# and java?
I tend to use Nullable types wherever they make sense -- I won't care about performance until it's a problem, then I'll fix the few areas where it is and be done with it.
However, I also find that in general, most of my values end up being non-nullable. In fact, there are many times I'd actually like a NotNullable I can use with reference types to find out about a null problem when I get the null, not later on when I try to use it.
The only time that a Nullable Type should ever be used, is in the case that a certain field in a table of the database absolutely requires that a null be sent or received by the application at some point. Even in such a case, one should always try to find a way around using the Nullable Type. Bool isn't always your best friend.