枚举、标记和C#

原文地址: http://www.codeproject.com/Articles/37921/Enums-Flags-and-Csharp-Oh-my-bad-pun.aspx
我不知道其他人怎么样,但是我就是喜欢枚举类型。而且,我也喜欢和枚举结合在一起的Flags Attribute(不知道翻成什么好)。本文将探讨配合着扩展方法如何使用二者来使你的代码更紧凑、易懂。
如果你从来没有将二者结合起来过,请不要错过。考虑下面的代码:
class  User {
    
bool  CanDelete;
    
bool  CanRead;
    
bool  CanWrite;
    
bool  CanModify;
    
bool  CanCreate;
}
好的,这个看起来没什么大不了的,甚至还可能是几行额外的代码。如果能够将所有的那些权限都组合到一个值里,那就再好不过了。我们可以用一个带有FlagAttribute的枚举类型来解决这个问题。
enum  PermissionTypes :  int  {
    None 
=   0 ,
    Read 
=   1 ,
    Write 
=   2 ,
    Modify 
=   4 ,
    Delete 
=   8
    Create 
=   16 ,
    All 
=  Read  |  Write  |  Modify  |  Delete  |  Create
}

// and the class from before
class  User {
    PermissionTypes Permissions 
=  PermissionTypes.None;
}
上面这个枚举的优点就在于我们可以将多个值分配到相同的属性。不仅如此,我们还可以通过比较,对已存值进行检测。
// create a new user
User admin  =   new  User();
admin.Permissions 
=  PermissionTypes.Read
    
|  PermissionTypes.Write
    
|  PermissionTypes.Delete;

// check for permissions
bool  canRead  =  ((PermissionTypes.Read  &  admin.Permissions)  ==  PermissionTypes.Read);
bool  canWrite  =  ((PermissionTypes.Write  &  admin.Permissions)  ==  PermissionTypes.Write);
bool  canCreate  =  ((PermissionTypes.Create  &  admin.Permissions)  ==  PermissionTypes.Create);

// and the results
Console.WriteLine(canRead);  // true
Console.WriteLine(canWrite);  // true
Console.WriteLine(canCreate);  // false
现在代码看起来非常简短易读。但是,当你要检测一个值的时候,每次都需要把代码重写一遍。那还不是很糟,但是我真的不想经常的去敲代码。当然,你可以写一个单独的函数来做这个比较,但是相对而言,我们还更很好的方法。
发挥扩展方法的优势
因为枚举类型并不是一个类,所以,并不能对枚举类型进行方法扩展。然而,在System.Enum这个类里,是可以将方法扩展的。添加进这个类里的方法,会出现在所有的枚举类型中。
这里有一个例子:
// full class included at the end of the post
public   static   class  EnumerationExtensions {

    
// checks to see if an enumerated value contains a type
     public   static   bool  Has < T > ( this  System.Enum type, T value) {
        
try  {
            
return  ((( int )( object )type  &  
              (
int )( object )value)  ==  ( int )( object )value);
        }
        
catch  {
            
return   false ;
        }
    }
}
现在,这段代码假设枚举类型可以转化为整型。在做比较之前可以做一些类型检测,但是,这个例子的初衷是要保持代码简短。
那么,如何来使用这个扩展呢?
// start with a value
PermissionTypes permissions  =  PermissionTypes.Read  |  PermissionTypes.Write;

// then check for the values
bool  canRead  =  permissions.Has(PermissionTypes.Read);  // true
bool  canWrite  =  permissions.Has(PermissionTypes.Write);  // true
bool  canDelete  =  permissions.Has(PermissionTypes.Delete);  // false
现在,代码变得更加易读了。甚至,可以注意到,这个扩展有一个通用参数,在使用这个方法之前我们不必提供参数类型,因为方法本身能够根据参数推断出来。
同时,也要记住,System.Enum并不是唯一一个可以做这个的类,也有一些其他的类(如:System.Array),你可以在这些类中添加自己的扩展方法,你会有意想不到的收获。
正如我先前提到的,这段代码不可能涵盖所有情况,你需要根据需要修改它。例如,如果你使用long,uint,ulong,这段代码就不能胜任了。
你可能会感到奇怪,为什么我们在将一个参数转化为int类型之前,先要转换成object类型呢?当你和通用参数打交道的时候,你并不能立刻将其转换为值类型,你要么先转换为一个objec类型再转换为值类型,要么就直接转换为一个空值类型,如int。
下面是关于EnumerationExtensions类的所有代码。如果你有什么好的建议,请告知我。我目前正在进行修订来完善这段代码。
namespace  Enum.Extensions {

    
public   static   class  EnumerationExtensions {

        
// checks if the value contains the provided type
         public   static   bool  Has < T > ( this  System.Enum type, T value) {
            
try  {
                
return  ((( int )( object )type  &  ( int )( object )value)  ==  ( int )( object )value);
            }
            
catch  {
                
return   false ;
            }
        }

        
// checks if the value is only the provided type
         public   static   bool  Is < T > ( this  System.Enum type, T value) {
            
try  {
                
return  ( int )( object )type  ==  ( int )( object )value;
            }
            
catch  {
                
return   false ;
            }
        }

        
// appends a value
         public   static  T Add < T > ( this  System.Enum type, T value) {
            
try  {
                
return  (T)( object )((( int )( object )type  |  ( int )( object )value));
            }
            
catch (Exception ex) {
                
throw   new  ArgumentException(
                    
string .Format(
                        
" Could not append value from enumerated type '{0}'. " ,
                        
typeof (T).Name
                        ), ex);
            }
        }

        
// completely removes the value
         public   static  T Remove < T > ( this  System.Enum type, T value) {
            
try  {
                
return  (T)( object )((( int )( object )type  &   ~ ( int )( object )value));
            }
            
catch  (Exception ex) {
                
throw   new  ArgumentException(
                    
string .Format(
                        
" Could not remove value from enumerated type '{0}'. " ,
                        
typeof (T).Name
                        ), ex);
            }
        }
    }
}


转载于:https://www.cnblogs.com/kaihua/archive/2009/09/13/Enums-Flags-and-Csharp.html

你可能感兴趣的:(枚举、标记和C#)