一、MSDN描述
ValueType 类:提供值类型的基类
命名空间: System
程序集: mscorlib.dll
继承关系:
值类型包括:字符、整数、浮点、布尔、枚举、结构(其实字符、整数、浮点、布尔是结构,下面会说明)
二、值类型花名册
1. 字符
Char 结构: 表示一个 Unicode 字符。
命名空间: System
程序集 : mscorlib.dll
原型定义:
[SerializableAttribute]
[ComVisibleAttribute(true)]
public struct Char : IComparable, IConvertible, IComparable<char>, IEquatable<char>
在C# 中 char 是 System.Char 的别名
System.Char 继承 System.ValueType
using System; class App
{
static void Main()
{
var charType1 = typeof(Char);
var charType2 = typeof(char); // char 是 Char 在C#中的别名 Console.WriteLine(charType1);
Console.WriteLine(charType1.BaseType);
Console.WriteLine(charType2);
}
}
常用属性和方法:
IsDigit(Char) 是否是数字
IsLetter(Char) 是否是字母
IsLetterOrDigit(Char) 是否是数字或字母
2. 整数
分为有符号整数和无符号整数
有符号整数
SByte <--> sbyte 8位
Int16 <--> short 16位
Int32 <--> int 32位
Int64 <--> long 64位
无符号
Byte <--> byte
UInt16 <--> ushort
UInt32 <--> uint
UInt64 <--> ulong
3. 浮点
单精度
Single <--> float
双精度
Double <--> double
4. 布尔
Boolean <--> bool
5. 枚举
Enum 类:为枚举提供基类
命名空间: System
程序集 : mscorlib.dll
原型定义:
[SerializableAttribute]
[ComVisibleAttribute(true)]
public abstract class Enum : ValueType, IComparable, IFormattable, IConvertible
可以看出 Enum 是class
在C# 中 System.Enum 的别名为 enum
常见属性和方法:
Parse(Type, String) 解析枚举值
TryParse<TEnum>(String, TEnum)
6. 一些常见的结构 struct
1. Char、Int16、Int32、Int64、Single 、Double 以及无符号版本
2. IntPtr 结构:用于表示指针或句柄的平台特定类型
常用构造器:
IntPtr(Int32)
IntPtr(Int64)
var intPtr1 = new IntPtr();
var intPtrZero = IntPtr.Zero; // 代表已初始化为零的指针或句柄
3. Guid 结构: 表示全局唯一标识符 (GUID)
常用构造器:
Guid(String)
常用属性和方法:
Guid.Empty Guid 类的只读实例,其值保证均为零
Guid.NewGuid() 产生一个新Guid
Guid.Parse
Guid.TryParse
ToString
4. DateTime结构 : 表示时间上的一刻,通常以日期和当天的时间表示
System.DateTime 实例所表示的日期范围是在这两个日期之间:0001年1月1日午夜(一天开始之时)和9999年12月31日午夜
常用构造器
DateTime(int year,int month,int day)
DateTime(int year,int month,int day,int hour,int minute,int second)
常用静态属性
static DateTime Now {get;}
static DateTime Today{get;} // 返回日期实例,时间部分设为零
static DateTime UtcNow{get;}
常用实例属性
DateTime Date{get;} // 返回日期,时间部分设为0
DayOfWeek DoyWeek{get:} // 返回 System.DayOfWeek 枚举值
int DayOfYear{get;}
int Year{get:}
int Month{get:}
int Day{get;}
int Hour{get;}
int Minute{get:}
日期运算
AddYears(int year) // year 可为负 下面month day 之类类似
AddMonths(int month)
AddDays(int day)
AddHours(int hour)
AddMinutes(int minute)
AddSeconds(int second)
ToString 格式
常用格式 yyyy-MM-dd HH:mm:ss 其他格式参考MSDN
Parse方法与TryParse方法
代码如下 demo.cs
using System; class App
{
static void Main()
{
// 属性
Console.WriteLine("当前时间是 {0}",DateTime.Now);
Console.WriteLine("当前是 {0}",DateTime.Today);
DateTime now = DateTime.Now;
Console.WriteLine("Date {0}",now.Date);
Console.WriteLine("Year {0}",now.Year);
Console.WriteLine("Month {0}",now.Month);
Console.WriteLine("Day {0}",now.Day);
Console.WriteLine("Hour {0}",now.Hour);
Console.WriteLine("Minute {0}",now.Minute);
Console.WriteLine("Second {0}",now.Second);
Console.WriteLine("Day of Year {0}",now.DayOfYear);
Console.WriteLine("Day of Week {0}",now.DayOfWeek); // 运算操作
now = now.AddHours();
// AddYears AddMonths AddDays AddMinutes AddSeconds
Console.WriteLine("Date {0}",now.ToString("yyyy-MM-dd HH:mm:ss")); // Parse
DateTime dt1 = DateTime.Parse("2016-7-1 9:00");
Console.WriteLine("Date {0}",dt1.ToString("yyyy-MM-dd HH:mm:ss")); // TryParse
DateTime dt2 = DateTime.Now;
DateTime.TryParse("2016-7-1 9:30",out dt2);
Console.WriteLine("Date {0}",dt2.ToString("yyyy-MM-dd HH:mm:ss"));
}
}
编译 csc demo.cs
运行
5. TimeSpan结构:表示一个时间间隔
6. Nullable<T> 结构:表示基础类型为值类型的对象,值类型与引用类型一样也可以分配 null
==2014-12-22 编辑==
新增一副 System 命名空间下的继承关系图
(这幅图有个不好的地方,简单类型的也是 Struct 类型,这图没画出来)
==2015-1-3 编辑==
1、新增枚举类型的基本操作
2、类型转换
3、运行时候值类型与引用类型的内存分布
4、值类型的装箱(boxed)和拆箱(unboxed)
枚举类型基本操作
using System; class App
{
static void Main()
{
var e1 = (Person); // 值强转枚举类型
Console.WriteLine("The Type of Person: {0}",typeof(Person)); // 原始枚举类型
Console.WriteLine("Type :{0}\nItem :{1}\nValue:{2}",e1.GetType(),e1,(int)e1);
Console.WriteLine();
var e2 = (Person)Enum.Parse(typeof(Person),"刘备"); // 从枚举项到枚举类型
Console.WriteLine("Type :{0}\nItem :{1}\nValue:{2}",e2.GetType(),e2,(int)e2);
} enum Person
{
刘备=,
关羽=,
张飞=
}
}
效果:
类型转换
1、隐式转换(值类型、引用类型)
值类型:如整型 --> 浮点
引用类型: 子类替换父类
2、显式强转(值类型和引用类型均可)
(Type)Instance
3、as 和 is
as 仅用于引用类型以及可空类型,返回转换后的实例,如转换失败返回 null
对于可空类型 var instance = 1 as int?;
is 判断两个类型是否兼容(就是本类型,以及子类是父类等情况)
运行时候值类型与引用类型的内存分布
在程序运行的时候,值类型内存分布在执行这段代码的线程的线程栈上;引用类型内存分布在托管堆上。
看一个 《CLR Via C# 》的例子
class App
{
static void Main()
{
RefType r1 = new RefType{X = };
ValType v1 = new ValType{X = }; RefType r2 = r1; // 传递的是引入也就是内存指针,如下图
r2.X = ; // r1的X也会变为5
System.Console.WriteLine(r1.X); ValType v2 = v1; // 拷贝的值,占用线程栈的空间
v2.X = ;
System.Console.WriteLine(v1.X); // v1 的值不会改变 仍然是9
}
} // 值类型
struct ValType{public int X{get;set;}} // 引用类型
class RefType{public int X{get;set;}}
引用类型除了封装需要的值外,还有两个地方需要关注(类型对象指针和同步块索引)这是比引用类型多得地方
值类型的装箱(boxed)和拆箱(unboxed)
上面讲了值类型和引用类型在运行时的内存分布(值类型分布在线程栈上、引用类型分布在托管堆上)。
值类型到引用类型的过程叫装箱(boxed),这个过程是有编译器做的,它完成了以下工作:首先取出值类型(如上例说的结构ValType)中真正需要的字段和方法(上例中就是 public int X{get;set;}),然后建一个类把这些真正需要的东西塞到这个由编译器建立的类中,最后返回这个类的类型对象指针,以便你能访问到这块托管堆内存。
被装箱后的值类型类型到原本值类型的过程叫拆箱(unboxed),这个过程也是编译器完成的,过程和上面的过程大致相反:首先取出引用类型中真正需要的字段和方法,然后在线程栈上建立一个结构把这些真正需要的字段和方法塞到这个结构中,最后返回这个结构的名字,以便你能访问这个结构。
装箱和拆箱需要分配内存(这个过程比较耗时),频繁的装箱拆箱会降低程序的运行效率。
==2015-3-14 编辑==
现实中的值和引用 来之 C# In Depth
假定你在读一份非常棒的东西,希望一个朋友也去读它。为了避免被人投诉支持盗版,进一步假定它是公共领域中的一份文档。那么,需要为朋友提供什么才能让他读到文档呢?这完全取决于阅读的内容。
先假设你正在读的是一份真正的报纸。为了给你朋友一份,需要影印报纸的全部内容并交给他。届时,他将获得属于他自己的一份完整的报纸。在这种情况下,我们处理的是 值类型 的行为。所有信息都在你的手上,不需要从其他任何地方获得。制作了副本直呼,你的这份信息和朋友的那份都是各自独立的。可以在自己的报纸上添加一些注解,他的报纸根本不会改变。
再假设你正在读的是一个网页。与前一次相比,这一次,唯一的需要给你朋友的就是网页的URL。这是 引用类型 行为,URL代替引用。为了读到真正的文档,必须在浏览器中输入URL,并要求浏览器加载网页。另一方面,假如网页由某种原因发生了变化(如一个维基页面,你在上面添加了自己的注释),你和你的朋友再次通过浏览器载入页面时,都会看到这个变化。
未完