选择Enum类型的默认值而不必更改值


208

在C#中,是否可以在不更改值的情况下用属性修饰Enum类型或进行其他操作以指定默认值?无论出于何种原因,所需的数字可能都是一成不变的,并且仍然可以控制默认数字。

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

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

您是否可以更改int?,double?等的默认值?
2014年

2
@AR过去没有冒犯您的意思,但是将枚举与ints 进行抽象比较没有意义,仅因为它们恰好实现为数字类型。我们可以将枚举实现为字符串,并且不会改变它们的用处。我认为这里的答案是C#语言表达能力的限制;在“将值与受限制的集合区分开”的想法中,这种限制当然不是固有的。
jpaugh

1
@jpaugh我不是在“抽象”中比较枚举和整数。我提供了其他数据(包括字符串和其他引用)类型的示例,其中更改默认值没有任何意义。这不是一个限制,它是一种设计功能。一致性是您的朋友:)
AR

@AR点已采取。我想我花了太多时间将enums视为类型级别的构造,特别是作为总和类型(或参见此处。就是说,将每个枚举视为一个不同的类型,其中该类型的所有值都与其他每个枚举的值都不同。从这样的心态来看,枚举是不可能共享任何值的,并且实际上,当您认为默认值0可能对给定的枚举无效时,这种抽象就会瓦解,而这只是每个枚举的shoe角。
jpaugh

是的,我熟悉歧视工会。C#枚举不是,所以我不知道以如此高(且不正确)的级别考虑它们是否有帮助。虽然“求和类型”当然具有其优势,但枚举和枚举也具有优势(假设提供了适当的值)。例如myColor = Colors.Red | 颜色。蓝色。我的主要观点是,如果您想要c#的求和类型,请创建一个,而不是尝试重新利用枚举的概念。
AR

Answers:


349

enum(实际上,任何值类型)的默认值为0,即使这不是该值的有效值enum。无法更改。


13
另一种方式要问的问题,对于一个int的默认值是42,想想如何愚蠢的是声音......记忆是空白运行时,你得到它之前,枚举是结构记住
ShuggyCoUk

3
@DougS 1.不,但是承认你错了。2.他没有通过评论投票赢得任何声誉。
Aske B. 2012年

7
这些评论使我对该答案感到怀疑,因此我对其进行了测试并验证了该答案绝对正确。
伊恩·纽森

1
@JamesCurran但是,当不为枚举使用0值时,我会遇到“ MyProjectName.dll中发生了'System.NullReferenceException'类型的异常,但未在用户代码中处理。其他信息:对象引用未设置为对象的实例。” 错误。如何解决?注意:我使用扩展方法来显示枚举的描述,但不确定如何避免在此页面
杰克

64

任何枚举的默认值为零。因此,如果要将一个枚举数设置为默认值,则将其设置为零,并将所有其他枚举数设置为非零(如果有多个枚举数,则第一个值为零的枚举数将是该枚举的默认值值为零)。

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'

38

如果零不能用作正确的默认值,则可以使用组件模型为枚举定义解决方法:

[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#语言默认值,但提供了一种指示(并获取)所需默认值的方法。


抱歉,它对您不起作用。您可以添加更多信息吗?您需要使用System.ComponentModel添加该行;然后在Utilities类中编写GetDefaultEnum()函数。您正在使用什么版本的.net?
大卫

3
+1用于重用组件模型属性和干净的解决方案。我建议您更改else语句的最后一行,如下所示:return default(TEnum);。第一,它将减少较慢的Enum.GetValues(...).***调用,其次(也是更重要的),它将对任何类型,甚至是非枚举都通用。此外,您不限制将代码仅用于枚举,因此当在非枚举类型上使用时,这实际上可以解决潜在的异常。
Ivaylo Slavov

1
这可能是在所问问题的上下文中滥用默认值属性。提出的问题是有关自动初始化的值的,该值在建议的解决方案中不会更改。此属性用于与初始值不同的视觉设计师的默认值。没有人问视觉设计师的问题。
大卫·伯格

2
在MSDN文档中,确实没有任何内容是ComponentModel或DefaultAttribute是仅“可视设计器”的功能。作为公认的答案状态。简短的答案是“否,它不可能”,将枚举的默认值重新定义为0值以外的值。此答案是一种解决方法。
大卫

17

枚举的默认值是等于0的任何枚举。我不认为这可以通过属性或其他方式更改。

(MSDN说:“枚举E的默认值是表达式(E)0产生的值。”)


13
严格来说,甚至不需要使用此值进行枚举。零仍然是默认值。
马克·格雷韦尔

11

您不能,但是如果您愿意,可以做一些技巧。:)

    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

在隐式转换运算符中,您需要value + 1,否则现在default(Orientation)返回East。另外,将构造函数设为私有。好方法。
nawfal 2015年

10

另一种可能有用的方法-使用某种“别名”。例如:

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

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

1
这个建议很好,但是,正如其他答案中已经提到的那样,枚举的默认值是零。就您而言,该表达式Status s = default(Status);将不是任何状态成员,因为s它将具有的值(Staus) 0。后者可以直接编写,因为枚举可以转换为整数,但是在反序列化期间将失败,因为框架确保枚举始终反序列化为有效成员。如果你改变了你的行代码将完全有效的New = 10New = 0
Ivaylo Slavov

1
是。新= 0将起作用。我个人将避免不明确设置枚举成员。
德米特里·帕夫洛夫

7

实际上是一个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;

9
但是,在这种情况下,“小马”就是“猫”(例如,Console.WriteLine(Animals.Pony);印刷品“猫”)
詹姆斯·柯伦

16
实际上,您应该:从不指定任何值,或者指定所有值,或者仅指定第一个已定义成员的值。在这里发生的是:Cat没有值,它是第一个值,因此自动将其设置为0。Dog没有值,将其自动设置为PreviousValue + 1,即1。Poney有一个值,保留该值。所以猫=小马= 0,狗= 1.如果您有{猫,狗,小马= 0,青蛙}然后狗=青蛙= 1
user276648

4

The default value of enum is the enummember equal to 0 or the first element(if value is not specified) ...但是我遇到了在项目中使用枚举的关键问题,并且通过做以下事情克服了... ...我的需求与班级水平有何关系...

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

-1为故意不回答给定的问题。这不是一个明显的作业问题,这应该是您唯一不回答的唯一情况。
Xynariz

1
@Xynariz ..对不起。.我的评论被误认为是负面的,因为我的真实意图是要以其他方式提供解决方案...所以我更改了我的评论...:D
Moumit 2014年

2

枚举类型的默认值为0:

  • 默认情况下,第一个枚举数的值为0,并且每个后续枚举数的值都增加1。

  • 值类型枚举具有由表达式(E)0产生的值,其中E是枚举标识符。

您可以查看C#枚举的文档在这里,和C#的默认值表的文档在这里


1

如果将默认枚举定义为具有最小值的枚举,则可以使用以下命令:

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

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

firstEnum == Mine.

这不假定枚举值为零。


0

默认值为定义中的第一个。例如:

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

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

这将返回 His


哈哈; “默认值”为零。但!他说,默认值“零”仅是第一个命名值的默认符号。!因此换句话说,语言选择了默认语言而不是您。这也恰好是零是一个整数的默认值
。.lol– user1953264

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

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

如果将该属性设置为null,则在get上将返回Orientations.None。默认情况下,属性_orientation为null。


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

然后在代码中可以使用

public Orientation GetDefaultOrientation()
{
   return default(Orientation);
} 

14
/!\错误/!\ DefaultValueAttribute实际上并没有设置值,仅用于提供信息。然后由您来检查您的枚举,字段,属性...是否具有该属性。PropertyGrid使用它,以便您可以右键单击并选择“重置”,同样,如果您不使用默认值,则文本将以粗体显示-但是,您仍然必须手动将属性设置为所需的默认值。
user276648 2011年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.