c# meiju(摘)

第一篇文章

C# 枚举(enum)-基础

枚举提供成组的常数值,它们有助于使成员成为强类型以及提高代码的可读性。在 C# 中,使用enum 来声明枚举。

枚举分为简单枚举和标志枚举两种,将在第三节中详细介绍这二者。

基本语法示例

enum Day { Sun, Mon, Tue, Wed, Thu, Fri, Sat };

以下格式也可以:

enum Day
{
    Sun,
    Mon,
    Tue,
    Wed,
    Thu,
    Fri,
    Sat
};

枚举类型

枚举类型可以是:byte、sbyte、short、ushort、int、uint、long、ulong,如果没有指定类型,则默认为 int 类型。指定类型示例:

enum Day : byte { Sun, Mon, Tue, Wed, Thu, Fri, Sat };

枚举数的值

默认情况下,第一个枚举数的值为 0,后面每个枚举数的值在前一个枚举数的值基础上递增 1。当然,也可以自行指定,例如:

enum Day { Sun = 1, Mon, Tue, Wed, Thu, Fri, Sat };
enum Range { MIN = 0, MAX = 255 };
enum Range2 { MIN, M1 = 50, M2, MAX = 255 }; //MIN 为 0,M2 为 51

枚举数大小写敏感

比如以下枚举有两个枚举数:

enum EnumTest { Sun, sun }; //尽管如此,我们仍不推荐这样写

取枚举数的值

虽然枚举有类型,但取枚举数的值时,仍然需要进行类型转换。

public partial class _ENUM : System.Web.UI.Page
{
    enum Range { MIN = 0, MAX = 255 };
    protected void Page_Load(object sender, EventArgs e)
    {
        Response.Write(Range.MAX); //输出为:MAX
        Response.Write("<br>");
        Response.Write(((int)Range.MAX).ToString()); //输出为:255
    }
}

枚举不能放在函数中

枚举可以与类平级,也可以作为类的 field,但不能放在函数中。可以加 public 等修饰符。

C# 枚举(enum)-设计

以下是使用枚举时几条好的建议。

优先考虑使用枚举,而不是类的静态常量

比如:

public static class Day
{
    public static int Sun = 1;
    public static int Mon = 2;
    public static int Tue = 3;
    //...
}

应该使用如下的枚举:

enum Day { Sun = 1, Mon, Tue, Wed, Thu, Fri, Sat };

如果参数、返回值、变量等类型可以是枚举,则不要使用其它基础类型

比如:

Range r = Range.MAX; //好
int r = (int)Range.MAX; //不好

枚举命名

枚举一般使用名词或名词组合,简单枚举使用单数,标志枚举使用复数。

大多数情况下不需要更改枚举的默认类型

也就是说大多数情况下,使用 int(System.Int32)作为枚举类型。除非:

  • 枚举是标志枚举,且标志多于 32 个(此时 int 类型装不下)。
  • 枚举被非常大量且频繁地使用,为了节约空间使用小于 int 的类型。
  • 不得不使用其它类型的情况。

不要在枚举中设置哨兵

我们可能觉得在枚举的两端加上哨兵,这样在判断一个数是否在枚举中时,只需要判断是否在哨兵之中。非常不幸,我们不应该这么做,这破坏了枚举的意义。

enum Day {FirstValue, Sun, Mon, Tue, Wed, Thu, Fri, Sat, LastValue }; //FirstValue、LastValue 应该去掉

C# 枚举(enum)-简单枚举与标志枚举

  • 简单枚举包含的值不用于组合,也不用于按位比较。
  • 标志枚举应使用按位 OR 操作进行组合。

简单枚举

前面提到的 Day、Range 都可以称之为简单枚举,因为不能将他们各自的值组合起来。

标志枚举

标志枚举的设计有两点要注意。

  • 指明 FlagsAttribute,以指示可以将枚举作为位域(即一组标志)处理。
  • 枚举中各标志的值应该是以 2 的幂来赋值,即:1、2、4、8、16、32……

举个例子,假如我们在设计 Windows 窗口程序,窗口有最小化、最大化、关闭按钮,我们想任意组合显示,也就是说我们可以显示其中的任意 0 个或一个或多个按钮。

如果使用简单枚举,按照排列组合,我们要使用 1 + 3 + 3 + 1 = 8 个枚举数,如果这里不是三个按钮,而是四个按钮,枚举数就更多了。所以这样不现实。

为什么这里使用简单枚举不现实呢?因为简单枚举不能组合,采用标志枚举就可以轻松解决了。

[Flags]
public enum WindowStyle
{
    MINIMUM_BUTTON = 1, //十六进制表示为 0x0001
    MAXIMUM_BUTTON = 2,
    CLOSE_BUTTON = 4
}

我们在设置窗口样式时,利用 OR 自由组合:

WindowStyle ws = WindowStyle.MINIMUM_BUTTON | WindowStyle.CLOSE_BUTTON; //表示既有 MINIMUM_BUTTON 也有 CLOSE_BUTTON

这就是为什么标志的值要按 2 的幂排列的原因了,也是为什么标志多于 32 个时不能使用 int 类型的原因了。

通常我们为常用的标志组合提供特殊的枚举值

仍然以上述窗口为例,可知大多数情况下,我们均要显示这三个按钮,所以每次使用时都要用:

WindowStyle ws = WindowStyle.MINIMUM_BUTTON | MAXIMUM_BUTTON | WindowStyle.CLOSE_BUTTON;

实在有些繁琐,我们可以修改枚举为如下:

[Flags]
public enum WindowStyle
{
    MINIMUM_BUTTON = 1,
    MAXIMUM_BUTTON = 2,
    CLOSE_BUTTON = 4,
    ALL_BUTTON = 7
}

增加一个 ALL_BUTTON 为前三个标志的值。使用时直接用 ALL_BUTTON 就可以了。

第二篇文章:(在项目中的应用)

1、枚举其实可以理解为一个恒量的结合,又或者可以认为它是一种类型。比如以下枚举定义:

public enum MicrosoftTechnology    
{        
     CSharp,        
     ASPNETMVC,        
     SQLServer,      
     WCF,        
     SilverLight,  
}

此枚举默认值为int型,当然我们可以根据需要指定枚举的数据类型。比如 public enum MicrosoftTechnology: long{....} 等。MicrosoftTechnology枚举int值分别为 Csharp:0;ASPNETMVC:1;SQLServer:2;WCF:3;SilverLight:4, 以自增1的形式自动赋值。当然也可以指定每个枚举项的值。

2、枚举的位运算:

Flag特性表示枚举支持位运算。一般情况下我们用到的位运算符有:&(与)、|(或)、~(非)。

首先我们为枚举加上[Flags]特性后再指定枚举值。

将1、中的代码修改如下:

[Flags]  
public enum MicrosoftTechnology    
{        
         CSharp = 1,        
         ASPNETMVC = 2,        
         SQLServer = 4,      
         WCF = 8,        
         SilverLight = 16,  
}

这里指定枚举值主要是为了使用与、或、非这三个位运算符。将枚举值转化成二进制值:

CSharp: 1 = 0001

ASPNETMVC: 2 = 0010

SQLServer: 4 = 0100

WCF: 8 = 1000

SilverLight: 16 = 10000

举例说明:

如果某位开发者选择两项微软技术分别为CSharp和ASPNETMVC 用位运算表达为 0001 | 0010 = 0011。经过不懈的努力这位开发者掌握了以上两项技术“0011”。现在我们想通过位运算检测出这位开发者是否精通CSharp:代码为:

(MicrosoftTechnology.CSharp|MicrosoftTechnology.ASPNETMVC) & MicrosoftTechnology.CSharp 等同 (0001 | 0010 = 0011)& 0001 等于 0001(CSharp :1) 讲到这里我想您应该不难理解:为了对枚举运用位操作时指定枚举值的缘故了。非(~)操作符这里就留给读者自己实践了。

         二、为枚举进行本地化

通过.net泛型机制编写枚举本地化通用方法,代码如下:

/// <summary>
/// 本地化枚举通用方法
/// </summary>
/// <returns></returns>
/// <author>Ryanding</author>
private static string LocalizeEnumeration(object enumerator)
         {
             ResourceManager resources = new ResourceManager("resx文件名",
                         System.Reflection.Assembly.GetExecutingAssembly());
string name = String.Format("{0}.{1}.Text", enumerator.GetType().Name, enumerator);
string localizedDescription = resources.GetString(name);
if (localizedDescription == null)
                 return enumerator.ToString();
else
                 return localizedDescription;
         }
/// <summary>
/// 翻译枚举成中文
/// </summary>
public static List<KeyValuePair> GetEnumStringList<T>()
         {
string[] resultPrepare = Enum.GetNames(typeof(T));
             List<KeyValuePair> result = new List<KeyValuePair>();
Array.ForEach(resultPrepare, f => result.Add(new KeyValuePair
             {
                 Key = (int)(Enum.Parse(typeof(T), f)),
                 Value = LocalizeEnumeration(Enum.Parse(typeof(T), f))
             }
             ));
             return result;
         }

通过以上代码,可以认为枚举也是一种类型。这里通过泛型机制将枚举本地化统一处理。

三、枚举在ORM中提高程序可读性

以LinqToSQL来列举枚举在ORM中的作用:

在大中型系统中设计数据库表时,比如有一张Customer表,存在一字段CustomerType(int 型) 。

CustomerType 枚举定义如下:

public enum CustomerType    
{        
        Trader = 0,        
        Supplier = 1,      
        Logistics = 2,  
}

Customer表结构如下:

1

        LinqTosql debug如下:

1

可以看出LinqTosql 已经很“完美”的将LINQ语句解析成SQL语句。这样当我们的业务变得相对复杂,枚举状态数量也逐渐增加时,开发者无需硬记0,1,2,3这些到底代表数据的何种业务状态。通过枚举映射到ORM,我们的代码可读性进一步加强。当然更便于维护了!

第三篇文章:

从长远来看,创建枚举可以节省大量的时间,减少许多麻烦。使用枚举比使用无格式的整数至少有如下三个优势:

● 枚举可以使代码更易于维护,有助于确保给变量指定合法的、期望的值。

● 枚举使代码更清晰,允许用描述性的名称表示整数值,而不是用含义模糊的数来表示。

● 枚举使代码更易于键入。在给枚举类型的实例赋值时,VS.NET IDE会通过IntelliSense弹出一个包含可接受值的列表框,减少了按键次数,并能够让我们回忆起可能的值。

public enum FileStates{Begin=1,Pause=2,RollBack=3,Success=4};
枚举类型都是值类型。System.Enum是一个抽象类(abstract class),所有枚举类型都直接继承自它,当然也同时继承了它的所有成员。所有的值类型都是System.ValueType的后代,枚举类型也不例外,枚举类型直接继承自System.Enum,而System.Enum却又直接继承自System.ValueType的,所以,枚举类型也是System.ValueType的后代。
值类型都是System.ValueType的后代”,但System.ValueType的后代不全是值类型,System.Enum就是唯一的特例!在System.ValueType的所有后代中,除了System.Enum之外其它都是值类型。事实上,我们可以在.NET的源代码中找到System.Enum的声明:

None.gifpublic abstract class Enum : ValueType, IComparable, IFormattable, IConvertible

  • 1. 所有枚举类型(enum type)都是值类型。
  • 2. System.Enum和System.ValueType本身是引用类型。
  • 3. 枚举类型(enum type)都是隐式的直接继承自System.Enum,并且这种继承关系只能由编译器自动展开。但System.Enum本身不是枚举类型(enum type)。
  • 4. System.Enum是一个特例,它直接继承自System.ValueType,但本身却是一个引用类型。

A:枚举类型可以被装箱成System.Enum、System.ValueType、System.Object或者System.IConvertible、System.IFormattable、System.IComparable。

注意:在.NET 1.1上,枚举类型只能被装箱到System.Enum、System.ValueType、System.Object;而在.NET 2.0上,枚举类型还能被装箱到System.Enum所实现的三个接口:System.IConvertible、System.IComparable、System.IFormattable。对应的装箱操作既可以为隐式的也可以是显式的。
枚举类型与整数类型有一定的关系。事实上,每一个枚举类型都有与之相对应的整数类型,我们称该整数类型为底层类型(underlying type),默认的情况下使用,.NET使用System.Int32。当然,你可以手动将其指定为其他的整数类型:
能被指定为枚举的底层类型的只能是如下所列的整数类型:byte, sbyte, short, ushort, int, uint, long, ulong。
如果你没有手动指定成员的值的话,从上往下看,各成员的值为:0, 1, 2, ...。说罢了,就是一个非负整数等差数列,其初值为0,步长为1。例如:
public enum Alignment
ExpandedBlockStart.gif {
InBlock.gif      Left,    // 0
InBlock.gif      Center,    // 1
InBlock.gif      Right    // 2
ExpandedBlockEnd.gif  }
那么被赋值的成员的值就是你所指定的值。当然,无论你是否手动指定枚举成员的值,递增步长都不会变,总是为1。为了测试你是否理解,请说出下面枚举个成员的值以及你的判断理由(请用人脑而不是电脑来运行以下代码):
public enum DriveType : sbyte
ExpandedBlockStart.gif {
InBlock.gif      CDRom,
InBlock.gif      Fixed = -2,
InBlock.gif      Network,
InBlock.gif      NoRootDirectory = -1,
InBlock.gif      Ram,
InBlock.gif      Removable = Network * NoRootDirectory,
InBlock.gif      Unknown
ExpandedBlockEnd.gif  }
public enum CustomerKind
ExpandedBlockStart.gif {
InBlock.gif      Normal = 90,
InBlock.gif      Vip = 80,
InBlock.gif      SuperVip = 70,
InBlock.gif      InActive = 100
ExpandedBlockEnd.gif  }
None.gif
None.gif public class Customer
ExpandedBlockStart.gif {
InBlock.gif public readonly CustomerKind Kind;
InBlock.gif
InBlock.gif private double m_Payment;
InBlock.gif public double Payment
ExpandedSubBlockStart.gif {
InBlock.gif return m_Payment * (int)Kind / 100;
ExpandedSubBlockEnd.gif      }
为枚举CustomerKind的每个成员都赋了一个特定的值,该值其实就是顾客购物折扣百分率。而在Customer类中,Payment属性就通过强类型转换来获取枚举成员的值(也就是购物折扣率),并用于货款计算。从这里可以看出,获取枚举成员的值还可以通过强类型转换方式。
InBlock.gif
InBlock.gif // Code heredot.gif
ExpandedBlockEnd.gif  }
枚举类型可以强制转换为整数,整数也可以强制转换为枚举类型
Alignment a = (Alignment)1;但这种机制可能使你遇到一些麻烦
public static bool IsAlignment(Alignment a)
ExpandedBlockStart.gif {
InBlock.gif switch(a)
       {
    case Alignment.Left:
    case Alignment.Center:
    case Alignment.Right:
      return true;
    default:
      return false;
      }
ExpandedBlockEnd.gif  }
枚举类型转换(解析)成字符串类型
最简单的方法就是使用System.Enum的public override string ToString();  或者把枚举类型转换为IConvertible接口,再调用该接口的string ToString(IFormatProvider provider);
static void Main()
ExpandedBlockStart.gif {
InBlock.gif      Alignment a = Alignment.Right;
InBlock.gif      Console.WriteLine("Alignment is {0}.", a.ToString());
InBlock.gif
InBlock.gif      FontStyle fs = FontStyle.Bold | FontStyle.Underline;
InBlock.gif      Console.WriteLine("FontStyle is {0}.", fs.ToString());
ExpandedBlockEnd.gif  }
手动指定格式参数:Console.WriteLine("Alignment is {0}.", a.ToString("d"));
一个表示枚举成员的字符串,如何将其解析为对应枚举类型:
这时你就需要System.Enum的public static object Parse(  Type enumType, string value,  bool ignoreCase  );
static void Main()
ExpandedBlockStart.gif {
InBlock.gif string name = "Right";
InBlock.gif      Alignment a = (Alignment)Enum.Parse(typeof(Alignment), name, false);
InBlock.gif
InBlock.gif      Console.WriteLine(a.ToString());
InBlock.gif
InBlock.gif string names = "Bold, Italic, Underline";
InBlock.gif      FontStyle fs = (FontStyle)Enum.Parse(typeof(FontStyle), names, false);
InBlock.gif
InBlock.gif      Console.WriteLine(fs.ToString());
ExpandedBlockEnd.gif  }
不应该使用枚举的情况:None.gif
枚举类型表达了一种稳定的分类标准。当你查看.NET Framework BCL中的枚举类型,你会发现它们几乎没有任何改变的可能或者趋势,表现出一种稳定性。所以,当你所要表达的分类标准也同样具备这种稳定性时,你就可以考虑枚举类型了。那么什么情况下不使用枚举呢?一般说来,当分类标准不闭合时——即新的子分类随时有可能产生或者现有子分类随时有可能被替换——你就应该考虑使用其他的方式来表达了.

 

我的理解:枚举就像一个静态数据,基本上是固定的。

类似全局静态常量?

位运算应用能看懂,但想像不到在实际项目中如何使用。

转载于:https://www.cnblogs.com/axyz/archive/2011/01/26/1945142.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值