- 介绍
- 具体案例
- 指定枚举的基础类型
- 常量的标识位运算(Enum)
- 获取枚举中常量的名称
- 检查枚举实例中是否包含某个标志位
- 在运行阶段检索特性实例
- 总结
随着.net core
越来越流行,对.net core
基础知识的了解,实际应用等相关的知识也应该有所了解。所以就有了这篇文章,案例都是来自阅读的书籍,或者实际工作中感觉比较有用的应用。分享亦总结。
本文主要介绍 .net core
相关的面向对象编程案例。
【导语】
在声明枚举类型的时候,如果不指定其基础类型,则其常量值默认为 int
类型。在有特殊需求的情况下,可以明确指定枚举中常量值的基础类型。必须使用整数值的基础类型,如int
、byte
、uint
、long
、ulong
等,不能使用非整性的类型,如 double
。
【操作流程】
步骤1:新建控制台应用程序项目。
步骤2:声明一个枚举类型,指定其常量值基于 byte
类型。
public enum ReadMode : byte
{
NewFile = 1,
OpenCurrent = 2,
Saved = 3
}
步骤3:再声明一个枚举类型,常量类型为 uint
。
public enum PictureQt : uint
{
HQ = 4,
LQ = 12,
MQ = 7
}
指定枚举常量的基础类型使用半角冒号来表示,和类之间的基础相似。
常量的标识位运算(Enum)【导语】
因为枚举类型的基础类型是整数类型,因此,枚举的常量值之间也可以进行为运算。即按位“与”(And)、按位“或”(Or),以及取反(Not)、异或(Xor)等。
支持安危运算的枚举类型在声明时需要应用 FlagsAttribute
,例如以下形式。
[FlagsAttribute]
enum MultiHue : short
{
None = 0,
Black = 1,
Red = 2,
Blue = 4,
Green = 8
}
如果希望枚举类型的值支持位运算,不仅要在类型定义时使用FlagsAttribute
,还必须注意每个常量值的合理安排。一般来说,常量值是以 2 位底数的幂运算结果。例如 2、4、8、16、32 等。每个常量值只有作为标志的二进制位才为 1,其他位都为 0。
例如上面举例的 MultiHue
枚举,None
值的常量值为 0,转换为二进制为 0000
;Black
值的常量值转换为二进制为 0001
;Red值的常量值转换为二进制为0010;Blue
值的常量值转换为二进制为 0100
;Green
值的常量值转换为二进制为 1000
。
如果将 Black
和 Red
两个值组合,得到的结果为 0011
,如果将 Blue
和 Green
两个值进行组合,得到的结果为 1100
。如果将 MultiHue
枚举的所有值都进行组合,得到的结果为 1111
。
【操作流程】
步骤1:新建控制台应用程序项目。
步骤2:声明一个枚举类型,并应用 FlagsAttribute
,使其支持按位运算。
[Flags]
enum TrackItem
{
Track1 = 1,
Track2 = 2,
Track3 = 4,
Track4 = 8,
Track5 = 16
}
注意:虽然在不应用 FlagsAttribute
的情况下,枚举的常量值仍然能够进行按位运算,但是当调用枚举实例的 ToString
方法时,是无法正确返回常量值的名称的。如果应用了 FlagsAttribute
,调用 ToString
方法可以得到已经组合的常量名称列表,并以半角逗号隔开。
步骤3:在项目模板生成的 Program
类中声明一个静态方法,用于在屏幕上输出经过组合运算后的枚举实例的常量名称以及常量的二进制值。
static void OutputInfo(TrackItem t)
{
string p1 = t.ToString();
string p2 = Convert.ToString((int)t, 2).PadLeft(5, '0');
Console.WriteLine($"{p2,-4} -- {p1}");
}
步骤4:在 Main
方法中,声明几个枚举变量,并赋予经过组合后的枚举值,然后调用 OutputInfo
方法进行测试。
// 将 Track1 与 Track2 组合
TrackItem t1 = TrackItem.Track1 | TrackItem.Track2;
OutputInfo(t1);
// 将 Track3、Track4、Track5 进行组合
TrackItem t2 = TrackItem.Track3 | TrackItem.Track4 | TrackItem.Track5;
OutputInfo(t2);
// 将枚举中所有值都进行组合
TrackItem t3 = TrackItem.Track1 | TrackItem.Track2 | TrackItem.Track3 | TrackItemTrack4 | TrackItem.Track5;
OutputInfo(t3);
步骤5:运行应用程序项目,输出如下。
步骤6:在声明枚举类型的时候,是允许使用表达式的计算记过来给常量赋值的。可以在上面的 TrackItem
枚举中添加一个 AllTracks
常量,然后它的值就是前面 5 个常量的值的组合。
[Flags]
enum TrackItem
{
Track1 = 1,
Track2 = 2,
Track3 = 4,
Track4 = 8,
Track5 = 16,
AllTracks = Track1 | Track2 | Track3 | Track4 | Track5
}
获取枚举中常量的名称
【导语】
在 .NET
类库中有一个 Enum
类,它是枚举类型的隐式基类。在代码中声明枚举类型时无需要继承 Enum
类。Enum
类提供一系列方法(包含实例方法和静态方法),可以对枚举类型进行各种处理。例如,本实例需要获取枚举类型中常量的名称,在 Enum
类中有两个静态方法可以完成此功能。
其中,GetName
方法只能获取枚举类型中单个常量的名称, 因此调用该方法时需要提供一个具体的常量;而GetNames方法可以获取枚举类型中所有已经定义的常量的名称,以字符串数组的形式返回。
【操作流程】
步骤1:新建控制台应用程序项目。
步骤2:在 System
命名空间下有一个 DayOfWeek
枚举,它定义了一周七天的名称(从星期天到星期六)。可以使用 Enum
类的 GetNames
方法获取 DayOfWeek
枚举中所有的常量的名称。
string[] days = Enum.GetNames(typeof(DayOfWeek));
步骤3:使用foreach循环把字符串数组中的元素输出到屏幕上。
foreach(string d in days)
{
Console.WriteLine(d);
}
步骤4:运行应用程序项目,输出如下。
【导语】
枚举类型的常量值可以组合起来使用,在实际开发中,经常需要检查枚举实例中是否包含指定的标志位。例如,枚举类型 Demo
中定义了三个常量,分别命名为 A、B、C,假设声明了一个变量 k,并在赋值时将 A 和 B 组合。
Demo k = Demo.A | Deom.B;
在代码中有两种方法可以检查变量 k 的值中有没有包含 A。一种方法就是把变量 k和 Demo.A
的值进行按位“与”运算。由于“与”运算时只有两个标志位同时为 1 时才能得到结果 1,因此,把变量 k 与 Demo.A
的值进行按位“与”运算后,如果变量 k 中包含 A 的标志位,那么运算结果就所示 Demo.A
,因为其他标志位在运算后都是 0;如果变量 k 中没有包含 A 的标志位,那么跟 Demo.A
进行按位“与”运算后的结果就是 0。还有一种方法,可以调用枚举类型实例的 HasFlag
方法,通过参数传递要被检查的常量值,如果变量中包含指定的标志位,HasFlag
方法返回 true
,否则返回 false
。
【操作流程】
步骤1:新建控制台应用程序项目。
步骤2:声明一个枚举类型 Test
,并在其上面应用 FlagsAttribute
,表示它支持组合使用。
[Flags]
enum Test
{
Mode1, Mode2, Mode3
}
步骤3:声明一个枚举类型的变量,并将 Mode2
和 Mode3
两个常量组合赋值。
Test t = Test.Mode2 | Test.Mode3;
步骤4:使用 HasFlag
方法检查变量中是否包含了 Mode3
标志位。
bool b = t.HasFlag(Test.Mode3);
步骤5:在声明一个变量,并将 Mode1
、Mode2
、Mode3
三个常量组合赋值。
Test t2 = Test.Mode1 | Test.Mode2 | Test.Mode3;
步骤6:通过进行按位“与”运算来检查变量中是偶发包含 Mode1
标志位。
bool b2 = (t2 & Test.Mode1) == Test.Mode1;
在运行阶段检索特性实例
【导语】
特性类的作用是为了代码对象应用一些辅助的信息,因此在应用程序运行阶段,可以检查特性类实例的相关数据,对数据进行验证。
要实现在运行阶段检索特性,需要用到反射技术,即在运行时获取类型以及其成员相关的信息,然后在检查出已应用特性的对象。
通过 Type
类可以得到各种代码对象(类、方法、属性、字段等)的信息,它们的共同基类是 MemberInfo
类,通过 GetCustomAttribute
扩展方法(在 CustomAttributeExtensions
类中定义)可以直接检索到已应用的特性实例。
【操作流程】
步骤1:新建控制台应用程序项目。
步骤2:声明一个特性类,并指定它只能应用于属性成员。
[AttributeUsage(AttributeTargets.Property)]
public class MyAttribute : Attribute
{
public char StartChar { get; set; }
public int MaxLen { get; set; }
}
StartChar
属性用于指定一个字符,即规定目标属性值开头的第一个字符;MaxLen
属性用于设置属性值的最大字符串长度。
步骤3:声明一个测试类,并把 MyAttribute
用到 RawName
属性上。
public class Test
{
[My(StartChar = 'k', MaxLen = 7)]
public string RawName { get; set; }
}
RawName
属性应用 MyAttribute
后,必须一字符“k”开头限制它的值,并且长度不能大于 7。
步骤4:在 Program
类中声明一个静态方法,在运行阶段验证 Test
对象的属性值是否满足 MyAttribute
实例中所设定的限制。
static bool CheckTest(Test t, string property)
{
// 获取类型信息
Type type = t.GetType();
// 查找属性成员
PropertyInfo prop = type.GetProperty(property, BindingFlags.Public | BindingFlags.Instance);
if (prop == null)
{
return false;
}
// 获取特性
MyAttribute att = prop.GetCustomAttribute();
// 获取实例的属性值
string value = prop.GetValue(t) as string;
if (string.IsNullOrEmpty(value))
return false;
// 进行验证
if (value.StartsWith(att.StartChar) == false)
return false;
if (value.Length > att.MaxLen)
return false;
return true;
}
PropertyInfo
类表示与属性有关的信息,调用它的 GetValue
方法可以获取属性的当前值。将属性的当前值与 MyAttribute
实例中指定的值进行比较,可以检验属性值是否符合要求。
步骤5:在 Main
方法中实例化 Test
对象,为 RawName
属性设置一个测试值。
Test v = new Test { RawName = "k003d6ex915f" };
步骤6:调用 CheckTest
方法对以上 Test
实例的 RawName
属性进行验证。
bool b = CheckTest(v, nameof(Test.RawName));
if (b)
Console.WriteLine("验证通过。");
else
Console.WriteLine("验证失败。");
虽然 Test
对象的 RawName
数学系是以字符“k”开头,但是其长度已经超过 7,因此验证失败。
本文到这里就结束了,下一篇将介绍字符串处理的知识案例。