简体   繁体   中英

How to tell if an enum property has been set? C#

I have a class with an enum property like so:

public class Foo
{
    public Color ColorType {get;set;}
}

public enum Color
{
    Red,
    Green,
}

Now this class can be initialized like so:

var foo = new Foo();

without the ColorType property ever being set. Now, I'm trying to create a method and perform actions on whether that enum was ever set or not, for example I have a method

private void checkEnum(Foo foo)
{
    if(foo.ColorType !=null)
    {
        //perform these actions
    }else
    {
        //perform those actions
    }
}

however I get a warning saying that value will never be null and upon further research, if the enum is never set if will default to the first value which would be Red in my case, I was thinking about adding a value to my enum which would be 'not set' and make that value the first one, so if it hasnt been set then the enum will have the value 'not set', is there a better way of doing this, my proposed method seems like it could get messy

You can use one of two methods: default enum value or a nullable enum.

Default enum value

Since an enum is backed by an integer, and int defaults to zero, the enum will always initialize by default to the value equivalent to zero. Unless you explicitly assign enum values, the first value will always be zero, second will be one, and so on.

public enum Color
{
  Undefined,
  Red,
  Green
}

// ...

Assert.IsTrue(Color.Undefined == 0);  // success!

Nullable enum

The other way to handle unassigned enum is to use a nullable field.

public class Foo
{
   public Color? Color { get; set; }
}

// ...

var foo = new Foo();
Assert.IsNull(foo.Color);     // success!

You can make it so that the underlying private field is nullable, but the property is not.

Eg

class SomeClass
{
    private Color? _color; // defaults to null

    public Color Color
    {
        get { return _color ?? Color.Black; }
        set { _color = value; }
    }

    public bool ColorChanged
    {
        get { return _color != null; }
    }
}

That way if color == null you know it hasn't been set yet, and you are also stopping the user from setting it to null (or undefined as other answers specify). If color is null you have 100% certainty that the user has not set it ever.

Only catch is the default value returned by the get but you could always throw an excepting if it better matches your program.

You can also take it one step further by making it so that the set only sets the field if the given value is not equal to the default value (depending on your use case):

public Color Color
{
    get { return _color ?? Color.Black; }
    set
    {
        if (value != Color)
        {
            _color = value;
        }
    }
}

You have two real options. The first is to add an undefined value to enum. This will be the default value before the property is initialized.

1)

public enum Color
{
    Undefined,
    Red,
    Green,
}

With your check like:

private void checkEnum(Foo foo)
{
    if(foo.ColorType == Color.Undefined)
    {
        //perform these actions
    }else
    {
        //perform those actions
    }
}

2) Alternatively you can not add the undefined value and just make the property Nullable

public class Foo
{
    public Color? ColorType {get;set;}
}
public enum Color
{
    Red,
    Green,
}

And perform your check like:

private void checkEnum(Foo foo)
{
    if(!foo.ColorType.HasValue)
    {
        //perform these actions
    }else
    {
        //perform those actions
    }
}

Enums are Value Types , which means they are not references to an object stored somewhere else, and hence they cannot be null . They always have a default value just like int which will default to zero upon creation. I suggest two approaches:

  1. Add another enum entry called eg, None with value equal to zero. This way your enum value will default to None upon creation. Then you can check if(foo.ColorType != Color.None) .

  2. Make your Color property a nullable one like: public Color? ColorType { get; set; } public Color? ColorType { get; set; } public Color? ColorType { get; set; } . Now it will default to null and can be assigned the value null . Read more about nullable types here: MSDN - Nullable Types (C#) .

Try this:

private void checkEnum(Color color)
{
    if(string.IsNullOrEmpty(color.ToString()))
    {
        //value is not set
    }
     else
    {
        //value is set
    }
}

enum is a value type so it cannot be null, and the storage is generally an integer. If you want a undefined value for your type, you may have

public enum Color
{
    Undefined,
    Red,
    Green,
}

As you've discovered, enumerations in C# are value types (they are essentially integers) not reference types so they will not default to NULL but rather the lowest integer value in the enumeration. Don't lose sight of this relationship when dealing with enums as it's one of their most useful attributes. Always remember that whether you explicitly state it or not,

public enum Color
{
    Red,
    Green
}

equates to:

public enum Color
{
    Red = 0,
    Green = 1
}

Though you may of course give each enumeration member any integer value that you like.

As far as whether or not there is a better way of doing this, it really all depends on what "this" is, though there's nothing wrong with your suggestion of simply using the following enum setup:

public enum Color
{
    None = 0,
    Red,
    Green
}

Generally you want to use enums when you have a decidedly finite and discrete set of possible values that you want to be able to select from by name. For example, say I have a method that takes one of the 4 cardinal directions (North, East, South, West) as a parameter. I decide that I want to number each of the directions in clockwise order, starting with 0 for North.

public enum Direction
{
    North = 0,
    East,
    South,
    West
}

Now, instead of having my function take an integer parameter and trusting that I'll remember what each number refers to, I can now have the function take an enumeration member as a parameter and know immediately which direction I'm dealing with. For example:

getNeighbor(1);

reads much easier as:

getNeighbor(Direction.East);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM