Выбор значения по умолчанию для типа Enum без необходимости изменения значений

В C# возможно ли украсить тип Enum атрибутом или сделать что-то еще, чтобы указать, каким должно быть значение по умолчанию, без изменения значений? Требуемые числа могут быть установлены в камне по любой причине, и было бы удобно по-прежнему контролировать по умолчанию.

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

Orientation o; // Is 'North' by default.

14 ответов

Решение

По умолчанию для enum (фактически любой тип значения) равен 0 - даже если это недопустимое значение для этого enum, Это не может быть изменено.

Значение по умолчанию любого перечисления равно нулю. Поэтому, если вы хотите установить один перечислитель в качестве значения по умолчанию, то установите для него значение нуля, а для всех остальных перечислителей - ненулевое значение (первый перечислитель со значением ноль будет значением по умолчанию для этого перечисления, если существует несколько перечислителей). со значением ноль).

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'

Если вашим перечислителям не нужны явные значения, просто убедитесь, что первым перечислителем является тот, который вы хотите использовать в качестве перечислителя по умолчанию, поскольку "по умолчанию первый перечислитель имеет значение 0, а значение каждого последующего перечислителя увеличивается на 1." ( C# ссылка)

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

Orientation o; // initialized to 'None'

Если ноль не работает как правильное значение по умолчанию, вы можете использовать модель компонента, чтобы определить обходной путь для перечисления:

[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);
        }
    }
}

и тогда вы можете позвонить:

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

Примечание: вам нужно будет включить следующую строку в верхней части файла:

using System.ComponentModel;

Это не изменяет фактическое значение по умолчанию для языка C# перечисления, но дает возможность указать (и получить) желаемое значение по умолчанию.

По умолчанию для перечисления используется любое перечисление, равное нулю. Я не верю, что это можно изменить с помощью атрибутов или других средств.

(MSDN говорит: "Значение по умолчанию для перечисления E - это значение, полученное выражением (E)0.")

Еще один способ, который может быть полезен - использовать какой-то "псевдоним". Например:

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

    // Use Status.Default to specify default status in your code. 
    Default = New 
}

Вы не можете, но если хотите, можете сделать какой-то трюк.:)

    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;
    }

использование этой структуры как простого перечисления.
где вы можете создать pa == Orientation.East (или любое другое значение по умолчанию)
чтобы использовать сам трюк, вам нужно конвертировать из int по коду.
есть реализация:

        #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

На самом деле enumпо умолчанию это первый элемент в enum чья ценность 0,

Так, например:

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;

The default value of enum is the enummember equal to 0 or the first element(if value is not specified)... Но я столкнулся с критическими проблемами, используя enum в своих проектах, и преодолел их, выполнив что-то ниже... Как бы то ни было, моя потребность была связана с уровнем класса...

    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
    }

и получить ожидаемый результат

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

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

А что если значение поступает из БД.... Хорошо, в этом сценарии... передайте значение в функцию ниже, и она преобразует значение в перечисление... функция ниже обрабатывает различные сценарии, и это универсально... и поверьте мне, это так очень быстро.....:)

    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);
    }

Значением по умолчанию для типа перечисления является 0:

  • "По умолчанию первый перечислитель имеет значение 0, а значение каждого последующего перечислителя увеличивается на 1".

  • "Тип значения enum имеет значение, созданное выражением (E)0, где E - идентификатор перечисления".

Вы можете проверить документацию для перечисления C# здесь, а также документацию для таблицы значений C# по умолчанию здесь.

enum Orientations
{
    None, North, East, South, West
}
private Orientations? _orientation { get; set; }

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

Если вы установите для свойства значение null, будет возвращено значение Orientations.None при получении. Свойство _orientation по умолчанию имеет значение null.

Если вы определяете перечисление по умолчанию как перечисление с наименьшим значением, вы можете использовать это:

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

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

firstEnum == Mine.

Это не предполагает, что перечисление имеет нулевое значение.

The default is the first one in the definition. Например:

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

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

Это вернется His

В этом случае не полагайтесь на значение перечисления. Представьте метод расширения , затем вы можете использовать его так:

      Orientation.North.ToInt32();

А вот код:

      // Remove all the values from the enum
enum Orientation
{
    None,
    North,
    East,
    South,
    West
}

public static class OrientationExtensions 
{
    public static int ToInt32(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}")
    };
}
[DefaultValue(None)]
public enum Orientation
{
    None = -1,
    North = 0,
    East = 1,
    South = 2,
    West = 3
}

Тогда в коде вы можете использовать

public Orientation GetDefaultOrientation()
{
   return default(Orientation);
} 
Другие вопросы по тегам