Initialize enum with a null value - c#

How do i create an enum with a null value
ex:
public enum MyEnum
{
[StringValue("X")]
MyX,
[StringValue("Y")]
MyY,
None
}
where None value is null or String.Empty

You can try something like this:-
public MyEnum? value= null;
or you can try this:-
public MyEnum value= MyEnum.None;

As all the other answers said, you can't have an enum value be null.
What you can do is add a Description attribute (like your StringValue) which has a null value.
For instance:
public enum MyEnum
{
[Description(null)]
None = 0,
[Description("X")]
MyX,
[Description("Y")]
MyY
}
You can get the description of the Enum with the following function:
public static string GetEnumDescription(Enum value)
{
FieldInfo fi = value.GetType().GetField(value.ToString());
DescriptionAttribute[] attributes =
(DescriptionAttribute[])fi.GetCustomAttributes(
typeof(DescriptionAttribute),
false);
if (attributes != null && attributes.Length > 0)
return attributes[0].Description;
else
return value.ToString();
}
Usage:
MyEnum e = MyEnum.None;
string s2 = GetEnumDescription((MyEnum)e); // This returns null

use the "?" oeprator for a nullable type !!
public MyEnum? myEnum= null;

All enum types are value types and the different members are also derived from member types (the allowed types are byte, sbyte, short, ushort, int, uint, long, or ulong - as documented).
This means that members of an enumeration cannot be null.
One way to deal with a default enum value is to put the None value as the first value and setting it to a negative value (for signed enums) or 0.
public enum MyEnum
{
[StringValue(null)]
None = -1,
[StringValue("X")]
MyX,
[StringValue("Y")]
MyY
}
You can have a null reference to an enumeration if you declare a nullable instance - myenum?.

There is no such thing as an "enum with a null value". An enum in C# is just a named integer. In your case, None is just an alias for 2 (for completeness, MyX is 0 and MyY is 1). By default, the underlying data-type of an enum is int, but it can also be other integer-based primitive types of different sizes/sign.
If you want a "null" enum, you would have to use MyEnum?, aka Nullable<MyEnum>.

Related

Implicit operator isn't called for default of struct in C#

I'm implementing a C# variant of Haskell's Maybe and came across a weird issue where null and default has different implication on the value returned from an implicit conversion.
public class TestClass
{
public void Test()
{
Maybe<string> valueDefault = default;
Maybe<string> valueNull = null;
Maybe<string> valueFoobar = "foobar";
Console.WriteLine($"Default: (Some {valueDefault.Some}, None {valueDefault.None}");
Console.WriteLine($"Null: (Some {valueNull.Some}, None {valueNull.None}");
Console.WriteLine($"Foobar: (Some {valueFoobar.Some}, None {valueFoobar.None}");
}
}
public struct Maybe<T>
{
public T Some { get; private set; }
public bool None { get; private set; }
public static implicit operator Maybe<T>(T value)
{
return new Maybe<T>() {
Some = value,
None = value == null
};
}
}
The output being:
Default: (Some , None False)
Null: (Some , None True)
Foobar: (Some foobar, None False)
I was expecting both valueDefault and valueNull to be equal. But seems that null is converted while default isn't. I fixed the issue by replacing None with HasSome with a reversed boolean condition, but still the question remains.
Why is null and default treated differently?
Every type has a default value, including Maybe<T>. See this page for a list.
Maybe<string> valueDefault = default; will assign the default value of Maybe<string> to valueDefault. What's the default value of Maybe<string>? According to that page, since Maybe<string> is a struct, its default value is:
The value produced by setting all value-type fields to their default values and all reference-type fields to null.
So it's an instance of Maybe<string> with Some being null and None being false. false is the default value of bool.
The compiler doesn't try to use the default value of string, since that requires a further conversion to Maybe<string>. If it can just use the default value of Maybe<string>, why go the extra trouble, right?
You can force it to though:
Maybe<string> valueDefault = default(string);
null, on the other hand, gets converted to Maybe<string> because null is not a valid value of Maybe<string> (structs can't be null!), so the compiler deduces that you must mean null as string, and does the implicit conversion.
You might know this already, but you seem to be reinventing Nullable<T>
default always fills the memory of the struct with zero bytes. null is not a valid value for a value type, so the compiler discovers the implicit (Maybe<string>)(string)null cast.
Perhaps you could replace with;
public struct Maybe<T>
{
public T Some { get; private set; }
public bool None => Some == null;
...

A default( T ) enum value doesn't equal null

I'm a bit surprised to find that calling the constructor in:
class MyClass<T>
{
public MyClass()
{
if ( default( T ) == null )
Debugger.Break();
}
}
doesn't break when T is an enum type. Why? It seems that even for enums, default( T ) and null should be equivalent.
No value type is ever going to test as equal to null, unless it's Nullable<T> which has special compiler and language support to treat an unset value as null.
The default(T) where T is any value type, including an enum, is going to be whatever the 0-filled value for that type is. I.e. an actual value. Not null.
Additional reading:
How to set enum to null
What does default(object); do in C#?
You may also want to read through some of the other hits in this search: [c#] default value enum null
Because enum in .net is a value type. If you only want to find out if default(T) == null then you can check if it is a reference type instead.
class MyClass<T>
{
public MyClass()
{
if (typeof (T).IsClass)
{
Debugger.Break();
}
else if (typeof (T).IsValueType)
{
//do something
}
}
}

What happens with enum when it is not set?

I have the following cast:
int myInteger = (int)myItem.EnumValue;
Where the enum is:
public enum EnumValue
{
Yes= 0,
No = 1
}
From my observations it seems that when the EnumValue on myItem is not set, the value of EnumValue is on default set to Yes and subsequently cast to 0.
Why is the enum not null? Is my observation correct and why is it so?
Enum's are value types, so just like int's and other value types, they cannot be null. Instead their default value is the equivalent of 0 (since you've assigned an enum value of Yes to 0, that's the default value in this case).
If you want a nullable enum, use Nullable<EnumValue> or EnumValue? for short.
Further Reading
Value Types (C# Reference)
enum (C# Reference)
Nullable Types (C# Programming Guide)
Because enum variable is essentially a variable of enum underlying type. By default it is integer. Integer cannot have null value.
UPDATE: Under hood enum looks like
class public auto ansi sealed EnumValue extends [mscorlib]System.Enum
{
.field public static literal EnumValue Yes = int32(0x00000000)
.field public static literal EnumValue No = int32(0x00000001)
.field public specialname rtspecialname int32 value__
}
I.e. its a set of constants (which are inlined during compilation) and integer (by default) field which holds enum value. Thats why you can assign any integer value to variable of EnumValue type. That's why by default it has value 0. That's why it cannot be null.
Several answers suggest using a nullable enum, but you can also build similar logic into your enum without the overhead of the Nullable type:
public enum EnumValue
{
Unknown = 0,
Yes = 1,
No = 2
}
Since the enum's default value is 0, the default value is Unknown. Note that the default value is zero even if you don't define a field with the value zero, like this:
public enum EnumValue
{
Yes = 1,
No = 2
}
Why is enum not null?
Because enum is a value type, which can never be null.
The underlying type of an enumeration is always integral. From the docs:
Every enumeration type has an underlying type, which can be any
integral type except char. The default underlying type of enumeration
elements is int.
Since yours is based on int, the default value of the enum is the default value of an integer - which is zero.

What are Nullable Types in C#?

int? _fileControlNo = null;
public int? FileControlNo
{
get { return _fileControlNo; }
set { _fileControlNo = value; }
}
I'm getting a syntax error when I assign null values to the above properties.
objDPRUtils.FileControlNo =sArrElements.Value(3)==null ? null : Convert.ToInt32(sArrElements.Value(3));
Please, can anyone explain to me why the error occurs if I'm able to set null value in valuetype object using Nullable Type.
The results of the conditional operators need to be of the same type or types that can be implicitly convertible to each other.
In your case you have a null and an Int32 - these violate that requirement.
If instead of an Int32 you return a nullable Int32, the null can be implicitly converted to this type and your code will work (or alternatively, cast the null to an int?).
Cast your null to int?
objDPRUtils.FileControlNo =sArrElements.Value(3)==null ? (int?) null : Convert.ToInt32(sArrElements.Value(3));
The conditional operator needs to return result of the same type and in your case its not possible for null
this should work
sArrElements.Value(3)==null ? (int?)null : Convert.ToInt32(sArrElements.Value(3));
Nullable types are exactly what they say they are: simple value types that can also store a null value.
I would suggest that you do not need the last line of code at all. you should be able to get away with:
objDPRUtils.FileControlNo =sArrElements.Value(3);
If you really want to assign another value in case of null, use the null coalescing operator ??
objDPRUtils.FileControlNo =sArrElements.Value(3)??0;
which in this case, would assign the value 0 to the FileControlNo in case of the right hand side being null.
Try to assign directly like this :
objDPRUtils.FileControlNo =sArrElements.Value(3);
Your code mixes types null and Int32 cannnot be mixed in this instance like that. They need to be of the same type.
If you use int.TryParse and only attempt to set the value on success you will achieve the same result and can use HasValue on the field to determine if its null or not which is how nullable types are used typically
Silly example
class Program
{
private static int? _fileControlNo;
static void Main(string[] args)
{
string[] sArrElements = new string[] { "1", "2", "3", null };
int result;
if (int.TryParse(sArrElements[3], out result))
{
FileControlNo = result;
}
if (_fileControlNo.HasValue)
{
// do something here
}
}
public static int? FileControlNo
{
get { return _fileControlNo; }
set { _fileControlNo = value; }
}
}
you will note that your code inside the test for HasValue in this case will never execute because _fileControlNo cannot be set because tryParse always fails (change the indexer and that will change).

C# cast object of type int to nullable enum

I just need to be able to cast an object to nullable enum. Object can be enum, null, or int. Thanks!
public enum MyEnum { A, B }
void Put(object value)
{
System.Nullable<Myenum> val = (System.Nullable<MyEnum>)value;
}
Put(null); // works
Put(Myenum.B); // works
Put(1); // Invalid cast exception!!
How about:
MyEnum? val = value == null ? (MyEnum?) null : (MyEnum) value;
The cast from boxed int to MyEnum (if value is non-null) and then use the implicit conversion from MyEnum to Nullable<MyEnum>.
That's okay, because you're allowed to unbox from the boxed form of an enum to its underlying type, or vice versa.
I believe this is actually a conversion which isn't guaranteed to work by the C# spec, but is guaranteed to work by the CLI spec. So as long as you're running your C# code on a CLI implementation (which you will be :) you'll be fine.
This is because you're unboxing and casting in a single operation, which is not allowed. You can only unbox a type to the same type that is boxed inside of the object.
For details, I recommend reading Eric Lippert's blog: Representation and Identity.
a bit offtopic
For Those, who needs the result to be null when the value is not defined in the enum;
One should use either :
typeof(MyEnum).IsEnumDefined(val)
or
Enum.IsDefined(typeof(MyEnum), val)
Here is the usage example:
enum MyEnum { one = 1, three = 3, four=4 }
static MyEnum? CastIntAsNullableEnum(int value)
{
if (!Enum.IsDefined(typeof(MyEnum), value)) return null;
return (MyEnum?)value;
}
static void CastIntAsNullableEnumTest()
{
for(int i =0; i<=5; i++)
{
Console.WriteLine("converted {0} is {1}", i, CastIntAsNullableEnum(i));
}
}
Thanks to John Thiriet (johnthiriet.com) for the solution
When you are assigning a value to a nullable type you have to be aware that it is not the same as the underlying type(at least in this case). So in order to perform the cast you need to unbox first:
void Put(object value)
{
if (value != null)
{
System.Nullable<Myenum> val = (System.Nullable<MyEnum>)(MyEnum)value;
}
}

Categories

Resources