I have the following:
MyEnum? maybeValue = GetValueOrNull();
if (null != maybeValue)
{
MyEnum value = (MyEnum)maybeValue;
}
What I want to know is if that explicit (MyEnum) cast is necessary on an instance of type MyEnum?. This seems like a simple question, I just felt paranoid that there could possibly be some runtime error if I just did MyEnum value = maybeValue within that if statement.
For a nullable type, you can do
if (maybeValue.HasValue)
{
MyEnum value = maybeValue.Value;
}
Since you're using nullable types, try using
if(maybeValue.HasValue)
{
MyEnum value = maybeValue.Value; // no cast needed! Yay!
}
A number of answers have noted that using the Value property avoids the cast. This is correct and it answers the question:
is that explicit (MyEnum) cast necessary on an instance of type "MyEnum?" ?
However, we haven't addressed the other concern:
I just felt paranoid that there could possibly be some runtime error if I just did MyEnum value = maybeValue within that if statement.
Well, first off, you cannot simply assign a nullable value to a variable of its underlying type. You have to do something to do the conversion explicitly.
However, if you do so in the manner you describe -- checking whether there is a value first -- then this is safe. (Provided of course that no one is mutating the variable containing the nullable value between the call to HasValue and the fetch of the value.)
If you use ILDASM or some other tool to examine the generated code you will discover that casting a nullable value to its underlying type is simply generated as an access to the Value property; using the cast operator or accessing the Value property is a difference which actually makes no difference at all. The Value property accessor will throw if HasValue is false.
Use whichever syntax you feel looks better. I personally would probably choose the "Value" syntax over the cast syntax because I think it reads better to say "if it has a value, gimme the value" than "if it has a value, convert it to its underlying type".
I believe that when you define a variable as a nullable type, it adds a .HasValue property and a .Value property. You should be able to use those to avoid any casting.
You can rewrite your code like this
MyEnum? maybeValue = GetValueOrNull();
if (maybeValue.HasValue == true)
{
MyEnum value = maybeValue.Value;
}
Another option would be to set up your enum to have a Default (0) value and then you would be able to just do the following:
MyEnum value = GetValueOrNull().GetValueOrDefault();
However, this would require that your code have knowledge of what the default value means and possibly handle it differently from what the other enum types do.
Related
This question already has answers here:
What Is The Point of Value on Nullable Types In C#
(2 answers)
How to convert C# nullable int to int
(20 answers)
System.DateTime? vs System.DateTime
(6 answers)
Closed 1 year ago.
I can't seem to wrap my head around how nullability works in C# 8. In the below IF expression it is clear that myType is not null. Still I am getting a compiler error saying it might be MyType OR null instead of MyType.
public Method(MyType mytpe)
{
System.Console.WriteLine("Meh");
}
public class AwesomeType
{
public MyType? MyType { get; set; }
}
//...
var awesome = new AwesomeType();
var myType = awesome.MyType;
if (myType != null)
{
Method(myType); // CS1503 Cannot convert MyType? to MyType
}
The following works fine
var awesome = new AwesomeType();
var myType = awesome.MyType;
if (myType != null)
{
Method(myType.Value);
}
I thought the first approach ought to work because the compiler can infert non-nullability within the true block of the if condition. Why does the compiler still complain?
Why does the compiler still complain?
This has to do with how nullable objects work in C#. The ? operator denoting that an object can be null basically tells the compiler 'Hey compiler - this object might be null, and that's okay.'
What this does for you, for as an example with bool? is allow you to denote a state that is not normally intended.
Normally a bool can only be true and false and if it was never initialized it could be null. If the bool was never initialized accessing it's value would throw an NullReferenceException.
Meanwhile bool?(denoting nullable bool) says to the compiler 'if the bool is null, treat null as it's value, instead of throwing an exception and complaining it doesn't have a value.'(in a simplified sense)
The trick with using nullable types, is that they are not implicitly treated like their non-nullable types. They're basically completely different objects, until you say so.
When you think about it it makes a lot of sense. It would be pretty weird if you could set a normal bool, like bool isLightOn = true; and set it to isLightOn = null;, what would that even mean? Does the light turn off, no that's what false would be.., would it flash the light on and off? The compiler has no clue what you intend to happen when you set a variable to a value that variable doesn't normally use(like null). That's a good thing! It would cause all sorts of weird issues.
This leads into the issue you are having.
bool? isLightOn = false;
// compiler checks to see if a bool? can have a null state
// it determines that bool? can be true, false, or null
// it says this line is okay
if(isLightOn != null)
{
// compiler says the variable isn't null,
// but it still CAN be null, for example, if something within this code block changes it's value,
// or if that variable is accessed by another thread
// becuase of this the compiler will not consider this light
// as either true, false(a normal bool) it says 'there's still
// a possibility that by the time it's used it may not be
// either true, or false, therefor it should be considered as
// being maybe null in my eyes(the compiler).'
// compiler checks to see if the object you're passing as a parameter is a valid object
// compiler sees that your object can be true, false, or null
// compiler says 'if i give this method this object without asking the programmer if it's okay, it may break the program becuase the method doesn't know how to deal with null values'
TestLight(isLightOn);
// compiler checks to see if the object you're passing as a parameter is a valid object
// compiler sees that the programmer explicitly told it to ignore the null value and treat is as if it were false, and allows you to pass that variable as parameter
TestLight((bool)isLightOn);
}
void TestLight(bool lightOn)
{
}
When you check a nullable object if it's null, that just checking it's value. Since that's a valid state for the object to be in, the compiler goes about it's day and doesn't complain.
When you try actually use that value for something that uses a non-nullable object as a parameter, we run into that issue of, how is the compiler supposed to know what you want to do if the null object state isn't a valid state for that object?
So it treats the nullable and non-nullable versions of your object as completely different types, BUT with an explicit cast between the two.
The reason for this can be boiled down to you're trying to use a variable in a way that would lose information, or a lossy operation, if you will.
The compiler wont make an asumption that you want to ignore a valid value for the nullable object.
It forces you to say 'hey compiler, treat this nullable object like a non-nullable object, if it's value isn't expected, change it to an expected value(default). For bool? if the valid value was null and you said 'treat it like a non-nullable bool' (by using explicit casting (bool)bool?, the compiler would say 'Okay! null is basically default so that's it's new value when you pass it as a parameter'.
I am new to generics in C# and while reading a book stumbled upon an example:
var cars = from car in data.AsEnumerable()
where
car.Field<string>("Color") == "Red"
select new
{
ID = car.Field<int>("CarID"),
Make = car.Field<string>("Make")
};
The author says that car.Field<string>("Color") gives the additional compile-time checking comparing to (string)car["Color"]. But how does the compiler know that car.Field<string>("Color") is compilable for "Color" and not for "CarID"? Or there is some kind of another "additional compile-time checking" that I miss?
It doesn't give you any additional compile-time checking. If you use the wrong type, in both cases you'll get an exception during run-time.
But it can be useful to do additional stuff that simple cast can't. For example Field<int>("CarId") could call a method that converts the string in the field to an int.
And assuming you're talking about DataRow.Field<T>(), then, according to the documentation, it's useful mostly for dealing with null values and nullable types correctly.
The compiler doesn't know, your specifying that field "Color" is of type string. Internally, the Field<T>() method does it's magic to make that happen.
If you perform a cast ((string)car["Color"]) you could encounter a runtime exception if the field value cannot be converted to the destination type.
From memory, if you specify car.Field<string>("ColorID"), you will be able to safely convert int to string without any issues.
Specifically, the real benefit of car.Field<string>("Color") is that it encapsulates testing field values for equality with DBNull.Value, making your code cleaner and easier to read.
In your example, if the value of the "Color" field is null, the Field<T> extension method will return null, while car["Color"] will return DBNull.Value. You can't cast DBNull.Value to string, so the expression (string)car["Color"] raises an InvalidCastException in that case.
Before the development of the DataSetExtensions class, you would need a somewhat verbose expression to assign the value of that field to a string variable:
var color = DBNull.Value.Equals(car["Color"]) ? null : (string)car["Color"];
Another benefit of Field<T> is, as svick notes, that it enables you to work with nullable types and reference types using the same syntax.
Want to improve this post? Provide detailed answers to this question, including citations and an explanation of why your answer is correct. Answers without enough detail may be edited or deleted.
Is there a technical reason why there is no implicit conversion from DBNull to the various nullable and/or sql types? I understand why the conversions don't currently happen, but don't understand why an implicit conversion wasn't created at the time or added in subsequent versions of the framework.
Just to be clear, I'm looking for technical reasons, not "because that's they way they did it" or "I like it that way".
The most straightforward explanation comes from Microsoft's documentation:
CLR nullable types are not intended for storage of database nulls because an ANSI SQL null does not behave the same way as a null reference (or Nothing in Visual Basic).
Well, I don't know about the SqlTypes case, but there definitely are some technical reasons why adding an implicit conversion between DBNull.Value and values of Nullable<T> with HasValue = false wouldn't work.
Remember, DBNull is a reference type, and despite the fact that Nullable<T> acts like a reference type -- by pretending to be able to take on the null value -- it's actually a value type, with value semantics.
In particular, there's a weird edge case when values of type Nullable<T> are boxed. The behavior is special-cased in the runtime to box values of type Nullable<T> to a boxed version of T, not a boxed version of Nullable<T>.
As the MSDN documentation explains it:
When a nullable type is boxed, the common language runtime automatically boxes the underlying value of the Nullable(Of T) object, not the Nullable(Of T) object itself. That is, if the HasValue property is true, the contents of the Value property is boxed. When the underlying value of a nullable type is unboxed, the common language runtime creates a new Nullable(Of T) structure initialized to the underlying value.
If the HasValue property of a nullable type is false, the result of a boxing operation is Nothing. Consequently, if a boxed nullable type is passed to a method that expects an object argument, that method must be prepared to handle the case where the argument is Nothing. When Nothing is unboxed into a nullable type, the common language runtime creates a new Nullable(Of T) structure and initializes its HasValue property to false.
Now we get into a tricky problem: the C# language spec (§4.3.2) says we can't use an unboxing conversion to convert DBNull.Value into Nullable<T>:
For an unboxing conversion to a given nullable-type to succeed at run-time, the value of the source operand must be either null or a reference to a boxed value of the underlying non-nullable-value-type of the nullable-type. If the source operand is a reference to an incompatible object, a System.InvalidCastException is thrown.
And we can't use a user-defined conversion to convert from object to Nullable<T>, either, according to §10.10.3:
It is not possible to directly redefine a pre-defined conversion. Thus, conversion operators are not allowed to convert from or to object because implicit and explicit conversions already exist between object and all other types.
OK, you or I couldn't do it, but Microsoft could just amend the spec, and make it legal, right? I don't think so.
Why? Well, imagine the intended use case: you've got some method that is specified to return object. In practice, it either returns DBNull.Value or int. But how could the compiler know that? All it knows is that the method is specified to return object. And the conversion operator to be applied must be selected at compile time.
OK, so assume that there is some magical operator that can convert from object to Nullable<T>, and the compiler has some way of knowing when it is applicable. (We don't want it to used for every method that is specified to return object -- what should it do if the method actually returns a string?) But we still have an issue: the conversion could be ambiguous! If the method returns either long, or DBNull.Value, and we do int? v = Method();, what should we do when the method returns a boxed long?
Basically, to make this work as intended, you'd have to use the equivalent of dynamic to determine the type at runtime and convert based on the runtime type. But then we've broken another rule: since the actual conversion would only be selected at runtime, there's no guarantee that it would actually succeed. But implicit conversions are not supposed to throw exceptions.
So at this point, it's not only a change to the specified behavior of the language, a potentially significant performance hit, and on top of that it could throw an unexpected exception! That seems like a pretty good reason not to implement it. But if you need one more reason, remember that every feature starts out minus 100 points.
In short: what you really want here can't be done with an implicit conversion anyway. If you want the behavior of dynamic, just use dynamic! This does what you want, and is already implemented in C# 4.0:
object x = 23;
object y = null;
dynamic dx = x;
dynamic dy = y;
int? nx = (int?) dx;
int? ny = (int?) dy;
Console.WriteLine("nx.HasValue = {0}; nx.Value = {1}; ny.HasValue = {2};",
nx.HasValue, nx.Value, ny.HasValue);
I'm curious as to why the following code works (run under the VS debugger):
int? x = null;
null
x.HasValue
false
If x is indeed null, what instance does HasValue refer to? Is HasValue implemented as an extension method, or does the compiler special case this to make it magically work?
Because x isn't a reference type. The ? is just syntactic sugar for Nullable<T>, which is a struct (value type).
int? is actually a structure Nullable<int>. Hence this, your x cannot be null, because it is always instance of a structure.
Hand-waving answer: Nullable structs are magic.
Longer answer: Null is not actually what is represented by the value. When you assign null to a nullable struct, what you will see happen behind the scenes is different.
int? val = null; // what you wrote
Nullable<Int32> val = new Nullable<Int32>(); // what is actually there
In this case, an instance of the struct is created that has the T Value set to a default value and the bool HasValue property set to false.
The only time you will actually obtain a null reference from a Nullable<T> is when it is boxed, as a Nullable<T> boxes directly to T or null, depending upon if the value is set.
There are several meanings to null.
One in programming languages which present variables and memory in a pointer-based manner (which includes C#'s references though it hides some of the details) is "this doesn't point to anything".
Another is "this has no meaningful value".
With reference types, we often use the former to represent the latter. We might use string label = null to mean "no meaningful label. It remains though that it's still also a matter of what's going on in terms of what's where in memory and what's pointing to it. Still, it's pretty darn useful, what a shame we couldn't do so with int and DateTime in C#1.1
That's what Nullable<T> provides, a means to say "no meaningful value", but at the level below it's not null in the same way a null string is (unless boxed). It's been assigned null and is equal to null so it's logically null and null according to some other semantics, but it's not null in the "doesn't point to anything" implementation difference between reference and value types.
It's only the "doesn't point to anything" aspect of reference-type null that stops you from calling instance methods on it.
And actually, even that isn't strictly true. IL let's you call instance methods on a null reference and as long as it doesn't interact with any fields, it will work. It can't work if it needs (directly or indirectly) those fields since they don't exist on a null refernce, but it could call null.FineWithNull() if that method was defined as:
int FineWithNull()
{
//note that we don't actually do anything relating to the state of this object.
return 43;
}
With C# it was decided to disallow this, but it's not a rule for all .NET (I think F# allows it, but I'm not sure, I know unmanaged C++ allowed it and it was useful in some very rare cases).
When using int? x = null then x is assigned a new instance of Nullable<int> and ist value is set to null.
I don't exactly know the internals but I would assume that the assignment operator itself is somewhat overloaded.
A nullable type isn't actually null since it still doesn't get around the fact that value types can't be null. It is, instead, a reference to the Nullable<> struct (which is also a value type and can't be null).
More information here.
Basically, you're always referring to an instance of something when you use a nullable type. The default information returned by that reference is the stored value (or null if there is no stored value).
Nullable isn't really a reference type, and its instance methods are one of the places where this shows up. Fundamentally, it is a struct type containing a boolean flag and a value of the type it is a nullable of. The languages special-case various operators [to be lifting, or to consider (bool?)null false in some cases] and the null literal, and the runtime special-cases boxing, but apart from that it's just a struct.
It's a completely new type. Nullable is not T.
What you have is a generic class something like this:
public struct Nullable<T>
{
public bool HasValue { get { return Value != null; } }
public T Value { get; set; }
}
I'm sure there's more to it (particularly in the getter and setter, but that's it in a nutshell.
The nullable type (in this case: nullable int) has a property of HasValue which is boolean. If HasValue is True, the Value property (of Type T, in this case, an int) will have a valid value.
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)