Choosing the default value of an Enum type without having to change values
Asked Answered
A

14

233

In C#, is it possible to decorate an Enum type with an attribute or do something else to specify what the default value should be, without having the change the values? The numbers required might be set in stone for whatever reason, and it'd be handy to still have control over the default.

enum Orientation
{
    None = -1,
    North = 0,
    East = 1,
    South = 2,
    West = 3
}

Orientation o; // Is 'North' by default.
Aduwa answered 9/2, 2009 at 20:59 Comment(5)
Should you be able to change the default value for int?, double?, etc.?Militant
@Militant No offense to past you, but it doesn't make sense to compare enums to ints in the abstract, simply because they happen to be implemented as a numeric types. We could implement enums as strings, and it would not change their usefulness. I consider the answer here a limitation of the expressiveness of the C# language; the limitation is certainly not inherent in the idea of "distinguishing values from a restricted set."Torque
@Torque I'm not comparing enums to ints "in the abstract". I'm giving examples of other data (including strings and other reference) types where changing the defaults makes no sense. It's not a limitation, it is a design feature. Consistency is your friend :)Militant
@Militant Point taken. I suppose I spend too much time thinking of enums as type-level constructs, specifically as sum types (or see here. That is, consider each enum as a distinct type, where all values of that type are distinct from every other enum's values. From such a mindset, it is impossible for enums to share any value, and indeed, this abstraction falls apart when you consider that the default of 0 may or may not be valid for a given enum, and is simply shoe-horned into every enum.Torque
Yes, I am familiar with discriminated unions. C# Enums aren't that, so I don't know if it is helpful to think of them at such a high (and incorrect) level. While a 'sum type' certainly has its advantages, so does and enum (assuming appropriate values are provided). e.g. myColor = Colors.Red | Colors.Blue. My main point is that if you want a sum type for c#, make one, rather than trying to repurpose the concept of an enum.Militant
T
388

The default for an enum (in fact, any value type) is 0 -- even if that is not a valid value for that enum. It cannot be changed.

Tyeshatyg answered 9/2, 2009 at 21:1 Comment(5)
Rephrase the question to ask that the default value for an int be 42. Think how daft that sounds... Memory is blanked by the runtime before you get it, enums are structs rememberCatchup
@DougS 1. No, but admitting you were wrong is. 2. He didn't earn any reputation from comment upvotes.Lunitidal
The comments made me suspicious about this answer, so I tested it and verified that this answer definitely is correct.Segmental
@JamesCurran But when not using 0 values for enums I encounter "An exception of type 'System.NullReferenceException' occurred in MyProjectName.dll but was not handled in user code. Additional information: Object reference not set to an instance of an object." error. How to fix it? Note: I use an extension method in order to display enum's Descriptions, but not sure how to avoid the error in the helper method (GetDescription) defined on this pageCamillacamille
So what happens if a variable of type MyEnum { SingleMember = 10 } defaults to zero? The answer is nothing. C# has no problem with MyEnum e having a value of zero even though the enumeration doesn't define it. It just doesn't have a name associated with it.Unbelt
B
70

The default value of any enum is zero. So if you want to set one enumerator to be the default value, then set that one to zero and all other enumerators to non-zero (the first enumerator to have the value zero will be the default value for that enum if there are several enumerators with the value zero).

enum Orientation
{
    None = 0, //default value since it has the value '0'
    North = 1,
    East = 2,
    South = 3,
    West = 4
}

Orientation o; // initialized to 'None'

If your enumerators don't need explicit values, then just make sure the first enumerator is the one you want to be the default enumerator since "By default, the first enumerator has the value 0, and the value of each successive enumerator is increased by 1." (C# reference)

enum Orientation
{
    None, //default value since it is the first enumerator
    North,
    East,
    South,
    West
}

Orientation o; // initialized to 'None'
Bushy answered 9/3, 2010 at 14:26 Comment(0)
T
49

If zero doesn't work as the proper default value, you can use the component model to define a workaround for the enum:

[DefaultValue(None)]
public enum Orientation
{
     None = -1,
     North = 0,
     East = 1,
     South = 2,
     West = 3
 }

public static class Utilities
{
    public static TEnum GetDefaultValue<TEnum>() where TEnum : struct
    {
        Type t = typeof(TEnum);
        DefaultValueAttribute[] attributes = (DefaultValueAttribute[])t.GetCustomAttributes(typeof(DefaultValueAttribute), false);
        if (attributes != null &&
            attributes.Length > 0)
        {
            return (TEnum)attributes[0].Value;
        }
        else
        {
            return default(TEnum);
        }
    }
}

and then you can call:

Orientation o = Utilities.GetDefaultValue<Orientation>();
System.Diagnostics.Debug.Print(o.ToString());

Note: you will need to include the following line at the top of the file:

using System.ComponentModel;

This does not change the actual C# language default value of the enum, but gives a way to indicate (and get) the desired default value.

Thanatos answered 9/2, 2009 at 20:59 Comment(4)
sorry it doesn't work for you. Can you add more info? you need to add the line using System.ComponentModel; and then write the GetDefaultEnum() function in a Utilities class. What version of .net are you using?Thanatos
+1 for the reuse of the component model attribute and the clean solution. I'd like to recommend you to change the last line in the else statement as follows: return default(TEnum);. Fist, it will reduce the slower Enum.GetValues(...).*** calls, second (and more important) it will be generic for any type, even non-enums. Besides, you do not restrict the code to be used for enums only, so this will actually fix potential exceptions when used over non-enum types.Masson
This may be a misuse of the default value attribute in the context of the question asked. The question asked is about the automatically initialized value, which won't change with the proposed solution. This attribute is meant for a visual designer's default differing from the initial value. There is no mention by the person asking the question of visual designer.Silvern
There really is nothing in MSDN documentation that the ComponentModel or DefaultAttribute is a "visual designer" only feature. As the accepted answer states. The short answer is "no, its impossible" to redefine the default value of an enum to something other than the 0 value. This answer is a workaround.Thanatos
N
17

An enum's default is whatever enumeration equates to zero. I don't believe this is changeable by attribute or other means.

(MSDN says: "The default value of an enum E is the value produced by the expression (E)0.")

Naraka answered 9/2, 2009 at 21:4 Comment(1)
Strictly, there doesn't even need to be an enumeration with this value. Zero is still the default.Snowinsummer
I
15

One more way that might be helpful - to use some kind of "alias". For example:

public enum Status
{
    New = 10,
    Old = 20,
    Actual = 30,

    // Use Status.Default to specify default status in your code. 
    Default = New 
}
Isleen answered 22/3, 2013 at 9:26 Comment(2)
The suggestion is good, however, as mentioned already in other answers, enumerations have their default value to be zero. In your case, the expression Status s = default(Status); will not be any of the status members, as s it will have the value of (Staus) 0. The latter is valid to write directly, as enums can be cast to integers, but it will fail during deserialization, as the framework makes sure that an enum is always deserialized to a valid member. Your code will be perfectly valid if you change the line New = 10 to New = 0.Masson
Yes. New = 0 would work. I would personally avoid not setting enum members explicitly.Isleen
U
11

You can't, but if you want, you can do some trick. :)

    public struct Orientation
    {
        ...
        public static Orientation None = -1;
        public static Orientation North = 0;
        public static Orientation East = 1;
        public static Orientation South = 2;
        public static Orientation West = 3;
    }

usage of this struct as simple enum.
where you can create p.a == Orientation.East (or any value that you want) by default
to use the trick itself, you need to convert from int by code.
there the implementation:

        #region ConvertingToEnum
        private int val;
        static Dictionary<int, string> dict = null;

        public Orientation(int val)
        {
            this.val = val;
        }

        public static implicit operator Orientation(int value)
        {
            return new Orientation(value - 1);
        }

        public static bool operator ==(Orientation a, Orientation b)
        {
            return a.val == b.val;
        }

        public static bool operator !=(Orientation a, Orientation b)
        {
            return a.val != b.val;
        }

        public override string ToString()
        {
            if (dict == null)
                InitializeDict();
            if (dict.ContainsKey(val))
                return dict[val];
            return val.ToString();
        }

        private void InitializeDict()
        {
            dict = new Dictionary<int, string>();
            foreach (var fields in GetType().GetFields(BindingFlags.Public | BindingFlags.Static))
            {
                dict.Add(((Orientation)fields.GetValue(null)).val, fields.Name);
            }
        } 
        #endregion
Unaneled answered 15/10, 2009 at 2:16 Comment(1)
In your implicit conversion operator you need value + 1, otherwise now your default(Orientation) returns East. Also, make the constructor private. Good approach.Jeremie
D
7

Actually an enum's default is the first element in the enum whose value is 0.

So for example:

public enum Animals
{
    Cat,
    Dog,
    Pony = 0,
}
//its value will actually be Cat not Pony unless you assign a non zero value to Cat.
Animals animal;
Drawback answered 15/10, 2009 at 0:34 Comment(2)
However, in that case "Pony" IS "Cat" (e.g, Console.WriteLine(Animals.Pony); prints "Cat")Tyeshatyg
Actually you should either: never specify any value OR specify all values OR only specify the value of the first defined member. Here what happens is that: Cat has no value and it's the 1st value, so automatically sets it to 0. Dog has no value, automatically sets it to PreviousValue + 1 ie 1. Poney has a value, leave the value. So Cat = Pony = 0, Dog = 1. If you have {Cat, Dog, Pony = 0, Frog} then Dog = Frog = 1.Testamentary
U
4

The default value of enum is the enummember equal to 0 or the first element(if value is not specified) ... But i have faced critical problems using enum in my projects and overcome by doing something below ... How ever my need was related to class level ...

    class CDDtype
    {
        public int Id { get; set; }
        public DDType DDType { get; set; }

        public CDDtype()
        {
            DDType = DDType.None;
        }
    }    


    [DefaultValue(None)]
    public enum DDType
    {       
        None = -1,       
        ON = 0,       
        FC = 1,       
        NC = 2,       
        CC = 3
    }

and get expected result

    CDDtype d1= new CDDtype();
    CDDtype d2 = new CDDtype { Id = 50 };

    Console.Write(d1.DDType);//None
    Console.Write(d2.DDType);//None

Now what if value is coming from DB .... Ok in this scenario... pass value in below function and it will convertthe value to enum ...below function handled various scenario and it's generic... and believe me it is very fast ..... :)

    public static T ToEnum<T>(this object value)
    {
        //Checking value is null or DBNull
        if (!value.IsNull())
        {
            return (T)Enum.Parse(typeof(T), value.ToStringX());
        }

        //Returanable object
        object ValueToReturn = null;

        //First checking whether any 'DefaultValueAttribute' is present or not
        var DefaultAtt = (from a in typeof(T).CustomAttributes
                          where a.AttributeType == typeof(DefaultValueAttribute)
                          select a).FirstOrNull();

        //If DefaultAttributeValue is present
        if ((!DefaultAtt.IsNull()) && (DefaultAtt.ConstructorArguments.Count == 1))
        {
            ValueToReturn = DefaultAtt.ConstructorArguments[0].Value;
        }

        //If still no value found
        if (ValueToReturn.IsNull())
        {
            //Trying to get the very first property of that enum
            Array Values = Enum.GetValues(typeof(T));

            //getting very first member of this enum
            if (Values.Length > 0)
            {
                ValueToReturn = Values.GetValue(0);
            }
        }

        //If any result found
        if (!ValueToReturn.IsNull())
        {
            return (T)Enum.Parse(typeof(T), ValueToReturn.ToStringX());
        }

        return default(T);
    }
Unmuzzle answered 3/12, 2013 at 13:31 Comment(2)
-1 for intentionally not answering the given question. This is not an obvious homework problem, which should be the only case in which you intentionally don't answer.Heymann
@Heymann .. sorry guys.. my comments was negative mistakely because my real intention was to provide a solution in other way... So i changed my comments ... :DUnmuzzle
D
3

The default value for an enumeration type is 0:

  • "By default, the first enumerator has the value 0, and the value of each successive enumerator is increased by 1."

  • "The value type enum has the value produced by the expression (E)0, where E is the enum identifier."

You can check the documentation for C# enum here, and the documentation for C# default values table here.

Drizzle answered 15/5, 2014 at 14:13 Comment(0)
S
2

If you define the Default enum as the enum with the smallest value you can use this:

public enum MyEnum { His = -1, Hers = -2, Mine = -4, Theirs = -3 }

var firstEnum = ((MyEnum[])Enum.GetValues(typeof(MyEnum)))[0];

firstEnum == Mine.

This doesn't assume that the enum has a zero value.

Stichometry answered 28/9, 2017 at 8:36 Comment(0)
S
2
enum Orientations
{
    None, North, East, South, West
}
private Orientations? _orientation { get; set; }

public Orientations? Orientation
{
    get
    {
        return _orientation ?? Orientations.None;
    }
    set
    {
        _orientation = value;
    }
}

If you set the property to null will return Orientations.None on get. The property _orientation is null by default.

Sarraceniaceous answered 9/1, 2019 at 11:20 Comment(0)
A
0

The default is the first one in the definition. For example:

public enum MyEnum{His,Hers,Mine,Theirs}

Enum.GetValues(typeOf(MyEnum)).GetValue(0);

This will return His

Aerodynamics answered 28/9, 2011 at 11:34 Comment(1)
haha; the "default value" is zero. BUT! he says, the default value "zero" only happens to be the default symbol of the first named value; ! so in other words the language choose the default instead of you; this also just happens that zero is default value of an int.. lolJollification
L
0

Don't rely on the enum value in this case. Let None be 0 as a default.

// Remove all the values from the enum
enum Orientation
{
    None, // = 0 Putting None as the first enum value will make it the default
    North, // = 1
    East, // = 2
    South, // = 3
    West // = 4
}

Then use a method to get the Magic Number. You can introduce an Extension Method and use it like:

// Extension Methods are added by adding a using to the namespace
using ProjectName.Extensions;

Orientation.North.ToMagicNumber();

And here is the code:

namespace ProjectName.Extensions
{
    public static class OrientationExtensions 
    {
        public static int ToMagicNumber(this Orientation orientation) => oritentation switch
        {
            case None  => -1,
            case North => 0,
            case East  => 1,
            case South => 2,
            case West  => 3,
            _          => throw new ArgumentOutOfRangeException(nameof(orientation), $"Not expected orientation value: {orientation}")
        };
    }
}
Lateshalatest answered 9/8, 2021 at 7:45 Comment(0)
B
-7
[DefaultValue(None)]
public enum Orientation
{
    None = -1,
    North = 0,
    East = 1,
    South = 2,
    West = 3
}

Then in the code you can use

public Orientation GetDefaultOrientation()
{
   return default(Orientation);
} 
Bugger answered 22/7, 2011 at 16:38 Comment(1)
/!\ WRONG /!\ The DefaultValueAttribute doesn't actually set the value, it's just for information purposes only. Then it's up to you to check whether your enum, field, property, ... has that attribute. The PropertyGrid uses it so that you can right click and select "Reset", also if you're not using the default value the text is shown in bold - BUT - you still have to manually set your property to the default value you want.Testamentary

© 2022 - 2024 — McMap. All rights reserved.