C#数据类型

变量数据类型

C# 的预定义类型(predefined type)或基元类型(primitive type)被视为其他所有类型的集合。

C#基本数值类型包括

  • 整数类型 8种


    整数类型
  • 科学计算的二进制浮点类型 2种


    浮点类型
  • 金融计算十进制浮点类型 1种


    浮点类型
  • 字符类型 1种

变量

  • 变量内置类型:intdoublestringcharbooldecimal
  • 变量使用规则:先声明,再赋值,最后使用。
  • 变量命名方式:Camel、Pascal

常量

  • 声明常量
const 变量类型 变量名=值
  • 常量不能被重新赋值

复杂数据类型

  • 类(classes)
  • 结构体(structures)
  • 枚举(Enumerations)
  • 接口(interfaces)
  • 委托(delegates)
类型派生谱系

枚举

枚举并非C#特有,与C语言中的枚举一样,C#中的枚举包含枚举值及与值关联的数字。所谓枚举,就是把这种类型数据可取的类一一列举出来。枚举类型是一种特殊的值类型,是一组已命名的数值常量,常用于声明一组命名的常数。枚举的类型必须是8种整形类型之一。

枚举是可由开发者声明的值类型,枚举的关键特征是在编译时声明了一组可通过名称来引用的常量值,使得代码更易懂。

声明枚举语法

[public] enum 枚举名
{
  值1,
  值2,
  值3...
}

- public 访问修饰符,默认为public公开的,表示无论什么位置都可以访问到。
- enum 关键字,声明枚举的关键字。
- 枚举名,需要符合Pascal命名规范。

枚举常声明在命名空间的下面类的外面,表示在这个命名空间下,所有的类都可以访问与使用它。

public enum UserState
{
    Online,
    Offline,
    Leave,
    Busy,
    CallMe
}

使用枚举替代布尔能改善代码的可读性,枚举类型默认可通过int类型相互转换,枚举类型跟int类型是兼容的。

enum ConnectionState
{
    Disconnected,
    Connecting,
    Connected,
    Disconnecting
}

使用枚举值需要为其附加枚举名称前缀

ConnectionState.Connected

根据约定,除了位标志之外的枚举名应该使用单数形式。

ConnectionState

枚举值实际是作为整数常量实现的,默认第一个枚举值为0,后续每一项都递增1,然而,可以显示地为枚举赋值。

enum ConnectionState:short
{
    Disconnected,
    Connecting = 10,
    Connected,
    Joined = Connected, 
    Disconnecting
}

枚举总是具有一个基础类型,可以是除了char之外的任意整型。事实上,枚举类型的性能完全取决于基础类型的性能。默认基础类型为int,但可以使用继承语法指定其他类型 。

枚举使用规范

  • 考虑在现有枚举中添加新成员,但要注意兼容性风险。
  • 避免创建代表不完整值几何的枚举
  • 避免在枚举中创建“保留给将来使用”的值
  • 避免包含单个值得枚举

枚举和其他类型稍有不同,因为枚举的继承链是从System.ValueTypeSystem.Enum,再到枚举。

枚举之间的类型兼容性

C#不支持不同枚举数组之间的直接转型,但CLR允许,前提是两个枚举具有相同的基础类型。为了避开C#的限制,一个可用的技巧是先转型为System.Array

可见枚举类型的变量跟intstring类型相互转换,枚举类型默认和int类型相互兼容,可通过强制类型转换的语法相互转换。但转换一个枚举中没有值的时候不会抛出异常,而是直接将数字显示。枚举和string类型那个相互转换时,若将枚举转换成string类型,则直接调用ToString(),若要将字符串转换为枚举,可采用:UserState state = (UserState)Enum.Parse(typeof(UserState), input)

enum UserState
{
    Online,
    Offline,
    Leave,
    Busy,
    CallMe
}

Console.Write("Input State Number: ");
string input = Console.ReadLine();
//将字符串转换成枚举类型,调用Parse()方法的目的是为了让其帮助我们将一个字符串转换成对应的枚举类型。
UserState state = (UserState)Enum.Parse(typeof(UserState), input);
Console.WriteLine(state); //0 Online

案例:输入选项输出选项值

enum Color
{
    Red,
    Green,
    Blue
}
while (true) { 
    Console.WriteLine("Input Option: [0]Red [1]Green [2]Blue");
    Console.Write("Option: ");
    string input = Console.ReadLine();
    switch (input)
    {
        case "0": 
        case "1":
        case "2":
            Color state = (Color)Enum.Parse(typeof(Color), input);
            Console.WriteLine($"State: {state}");
            break;
        default:
            Process.GetCurrentProcess().Kill();
            break;
    }
}

结构

  • 结构类型是一种值类型,是一种堆栈(stack)分配的复杂类型。
  • 结构类型不支持继承
  • 结构类型主要用于创建小型的对象,可节省内存。

结构可包含构造器、常量、字段、方法、属性、索引器、运算符、事件、嵌套类型等。若同时需要上述多个成员,则应该使用类。与类不同的是,结构是值类型,无需在堆(heap)中分配空间。而且结构不是引用类型,所以也不支持继承。

  • 类是引用类型,结构是值类型。
  • 结构是隐式密闭的,意味着结构不能被派生。

结构可帮助一次性声明多个不同类型的变量

[public] struct 结构名
{
  成员;
}

尽管可利用结构来简化类的声明和实现步骤,但并不是所有情况下都比类优越。作为值类型的结构在传递数据时,实际上是在传递数据本身的副本,而应用类型的类则传递的是引用地址。所以,但传递结构时会比传递类要慢,数据量越大差距就越明显。

public class Dimensions
{
  public double Length{get;set;|
  public double Width{get;set;}
}
public struct Dimensions
{
  public double Length{get;set;}
  public double Width{get;set;}
}

创建自定义值类型使用的是和定义类和接口相似的语法,区别在于值类型使用关键字struct。虽然语言本身未作要求,但对于使用值类型的的一种良好的规范是确保值类型是不可变的。换言之,一旦实例化值类型,实例就不能修改。若要需改则应创建新实例。这是因为:首先,值类型表示的是值。其次,因为值类型是按值复制的,而非按引用复制,所以很容易地迷惑或错误地认为,一个值类型变量的变化也会被观察到引起了另一个变量的变化。

struct Point
{
  public int x;
  public int y;
}

结构是值类型

  • 结构类型的变量不能为null
  • 两个结构变量不能引用同一个对象

虽然结构是值类型,但在语法上常常可将其视为类来处理。

var point = new Dimensions();
point.Length = 3;
point.Width =  4;

因为结构是值类型,所以new运算符和类和其他引用的工作方式不同。new运算符并不分配堆中的内存,只是调用相应的构造函数,根据传递给它的参数,初始化所有的字段。

Dimensions point;
point.Length = 3;
point.Width = 4;

结构的初始化

public struct Dimensions
{
  public double Length{get;set;}
  public double Width{get;set;}
  public Dimensions(double length, double width)
  {
    Length = length; 
    Width = width;
  }
  public double Diagonal => Math.Sqrt(Length * Length + Width * Width);
}

除了属性和字段,结构可包含方法和构造器,但不可以包含用户定义的默认无参构造器。每个结构自动获得一个无参构造器,将所有字段初始化为各自的默认值。被自动初始化了的结构变量会自动初始化变量。

由于编译器会将声明时的实例字段赋值放到类型的默认构造器中,所以C#禁止在声明时对结构的字段进行赋值。但这并不是表示无需对字段进行初始化。除非所有字段都初始化,否则结构类型的局部变量无法使用。

幸好C#支持有参构造器,而且它们提出了一个有趣的初始化要求。为了确保值类型的局部变量被完全初始化,每个构造器都必须初始化结构中的所有字段。

结构可以有实例构造函数和静态构造函数,但不允许有析构函数。

规范:要确保结构的默认值的有效,总是可以获得结果默认的全零的值。

对结构赋值

将一个结构赋值给另一个结构,也就是将一个结构的值赋值给另一个结构,这和复制类变量不同,复制类变量时只复制引用。

和类不同的是,结构不支持终结器。结构以值的形式复制,不像引用类型那样具有“引用同一性”,所以难以知道在什么时候能安全执行终结器并释放结构占用的非托管资源。垃圾回收器知道在什么时候不再有对一个引用类型实例的“活动”引用,可在此之后的任何时间为这个引用类型运行终结器。但是,“运行时”没有任何机制能够跟踪值类型在特定时刻有多少个副本。

获取类型默认值default

所有值类型都有自动定义的无参构造器将值类型的实例初始化成默认状态。所以,任何值类型都可合法地使用new S()的语法。除此之外,可使用default操作符生成结构的默认值。

值类型的继承和接口

所有的值类型都隐式封闭,除此之外,除了枚举之外的所有值类型都派生自System.ValueType,这意味着结构的继承链总是从objectSystem.ValueType到结构。

值类型也能实现接口,.NET Framework内建的许多值类型都实现了IComparableIFormattable等接口。

System.ValueType规定了值类型的行为,但没有包含任何附加成员。System.ValueType重写了object的所有虚成员。在结构中重写基类方法的规则与类基本一样。区别在于,对于值类型GetHashCode()的默认实现是将调用转发给结构中的第一个非空字段。此外,Equals()大量利用了反射。所以,加入一个值类型在集合中频繁使用,尤其是使用了散列码的字典类型的集合,那么值类型应该同时包含对Equals()GetHashCode()的重写,以确保获得较好的性能。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,098评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,213评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,960评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,519评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,512评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,533评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,914评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,804评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,563评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,644评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,350评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,933评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,908评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,146评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,847评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,361评论 2 342

推荐阅读更多精彩内容