# 特性
# System
# [Flags]
Flags 关键字使该枚举可进行位运算,可以让一个枚举类型中包含多个该枚举类型的值
假如有类型
| [Flags] |
| public enum Show |
| { |
| A = 0x00000001, |
| B = 0x00000010, |
| C = 0x00000100, |
| D = 0x00001000, |
| } |
合并多个,使用 |
| Show show=Show.A | Show.B |
判断是否存在某个值
| Show show=Show.A | Show.B; |
| show.HasFlag(Show.A); |
| |
| bool 包含=(show & Show.A)!=0; |
去掉一个值
| Show show=Show.A | Show.B; |
| show=show & (~Show.A); |
取反一个值
| Show show=Show.A | Show.B; |
| bool 包含=(show & Show.A)!=0; |
| if(包含) |
| { |
| show=show & (~Show.A); |
| } |
| else |
| { |
| show=show | Show.A; |
| } |
# System.ComponentModel
# [Description]
通常用于枚举的描述
| public enum Pepole |
| { |
| [Description("男孩")] |
| boy=1, |
| [Description("女孩")] |
| girl=2, |
| } |
可通过以下方法获取描述值
| Pepole pepole = Pepole.boy; |
| var des = pepole as DescriptionAttribute; |
| string value = des.Description; |
循环遍历获取
| foreach (var value in Enum.GetValues(typeof(Pepole))) |
| { |
| var fieldInfo = value.GetType().GetField(value.ToString()); |
| var attribArray = fieldInfo.GetCustomAttributes(false); |
| var attrib = attribArray[0] as DescriptionAttribute; |
| var des = des.Description; |
| } |
# 类型转化
# 隐式类型重载
可以将 B 类隐式转化为 A 类,如 float aaa=1.1,MyClass mc = aaa;
| public static implicit operator A(B b) |
| { |
| return new A(); |
| } |
# 字符串相关
# StringBuilder
# 变量和固定文本输入
| StringBuilder sb = new StringBuilder(); |
| sb.Append($"{我是变量}我是固定文本"); |
# 判断字符串是否以 xxx 结尾
| string a = "xxxxx"; |
| bool isEndWithXXX = a.EndsWith("xxx"); |
# 序列化相关
# 某个类序列化为二进制写入文件中
| FileStream fs = new FileStream("写入文件路径",FileMode.Create,FileAccess.ReadWrite,FileShare.ReadWrite); |
| BinaryFormatter bf = new BinaryFormatter(); |
| |
| bf.Serialize(fs,要转化成二进制的数据内容); |
| fs.Close(); |
反序列化过程与上类似,先加载二进制数据,在通过 bf.Deserialize (xxx) 获得该类
| MemoryStream stream = new MemoryStream(byte[] xxx); |
| BinaryFormatter bf = new BinaryFormatter(); |
| 反序列化类名 xxx = bf.Deserialize(stream) as 反序列化类名; |
# 变量相关
# 可变参数
| void function( params object[] args){} |
# @开头的变量名
在 C# 规范中, @ 可以作为标识符(类名、变量名、方法名等)的第一个字符,以允许 C# 中保留关键字作为自己定义的标识符。如
| class @class |
| { |
| public static void @static(bool @bool) { |
| if (@bool) |
| System.Console.WriteLine("true"); |
| else |
| System.Console.WriteLine("false"); |
| } |
| } |
这样,对于跨语言的移植带来了便利。因为,某个单词在 C# 中作为保留关键字,但是在其他语言中也许不是。
# C# 中的指针使用
C# 为了类型安全,默认并不支持指针。但是也并不是说 C# 不支持指针,我们可以使用 unsafe 关键词,开启不安全代码 (unsafe code) 开发模式。在不安全模式下,我们可以直接操作内存,这样就可以使用指针了。在不安全模式下,CLR 并不检测 unsafe 代码的安全,而是直接执行代码。unsafe 代码的安全需要开发人员自行检测。(原文链接)
| unsafe static void Main(string[] args){ |
| |
| } |
| |
| unsafe |
| { |
| |
| } |
# 指针类型
C# 可以定义为指针的类型有 sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, bool,struct,结构体中只能包括非托管类型
。
# 指针操作符
操作符 | 说明 |
---|
* | 取值运算符 |
& | 取址运算符 |
-> | 通过指针处理结构体中的数据(获取或赋值) |
++ 与 -- | 指针增、减操作 |
fixed | 用户暂时固定托管代码中引用类型的位置。 |
Stackallc | 分配内存 |
# fixed 应用
C# 在 GC 时在回收内存的同时会进行内存压缩,会导致堆中的地址重定向,如果使用了 fixed 关键字,那么就可以使当前内存地址跳过重定向,可用于操作类内的非托管类型
| class A{ |
| public int b; |
| } |
| |
| var a = new A(); |
| a.b=0; |
| fixed(int* aPtr=&a.b) |
| { |
| *aPtr += 1; |
| } |
| |
| |
# Stackallc 的应用
主动申请内存分配
| char* cptr = stackalloc char[26]; |
| for (int i = 0; i < 26;i++ ) |
| { |
| cptr[i] = (char) (i+65); |
| } |
| for (int i = 0; i < 26;i++ ) |
| { |
| Console.WriteLine(string.Format("{0}:{1}",(int)&cptr[i],cptr[i])); |
| } |
c# 并没有提供释放内存的函数,分配的内存会在方法结束后自动释放
# 指针定义
定义指针 | 说明 |
---|
int* p | 一个整型的指针 |
int** p | 指向整型指针的指针 |
int*[] arr | 整形一维数组的指针 |
# 指针的使用
# 整型指针
| int i=10; |
| int* iptr = &i; |
| Console.WriteLine((int)&iptr); |
| Console.WriteLine(*iptr); |
# 结构体指针
| struct Location |
| { |
| public int X; |
| public int Y; |
| } |
| unsafe static void Main(string[] args) |
| { |
| Location location; |
| location.X = 10; |
| location.Y = 5; |
| Location* lptr = &location; |
| Console.WriteLine(string.Format("location 地址{0},lptr地址{1},lptr值{2}",(int)&location,(int)lptr,*lptr)); |
| Console.WriteLine(string.Format("location.x的地址{0},location.x的值{1}",(int)&(lptr->X),lptr->X)); |
| Console.WriteLine(string.Format("location.y的地址{0},location.y的值{1}", (int)&(lptr->Y), lptr->Y)); |
| } |
# 指针与参数
| public static unsafe int* Add(int* x,int* y) |
| { |
| int sum = *x + *y; |
| return ∑ |
| } |
| |
| int i = 2, j = 3; |
| Console.WriteLine(*Add(&i,&j)); |
# 类与指针
c# 中的指针只能作用于非托管类型,因此无法声明类的指针,当类内存在非托管类型需要去操作时,可以使用指针 (参考 fixed 关键字)
| class People |
| { |
| public int Age; |
| public void ShowAge() |
| { |
| Console.WriteLine(Age); |
| } |
| } |
| |
| People people = new People(); |
| people.Age = 10; |
| fixed(int* agePtr=&people.Age) |
| { |
| *agePtr += 1; |
| } |
| people.ShowAge(); |
| |
# 访问类的内存地址
GCHandle 提供从非托管内存访问托管对象的方法
| using System.Runtime.InteropServices |
| |
| object p = new People(); |
| GCHandle h = GCHandle.Alloc(p, GCHandleType.Pinned); |
| IntPtr addr = h.AddrOfPinnedObject(); |
| Console.WriteLine(addr.ToString()); |
| h.Free(); |
# 序列化反序列化
# Xml
xml 序列化类
| using System.Xml.Serialization; |
| [System.Serializable] |
| public class TestSerilize |
| { |
| [XmlAttribute("Id")] |
| |
| public int Id { get; set; } |
| |
| [XmlAttribute("Name")] |
| |
| public string Name { get; set; } |
| |
| [XmlArray("List")] |
| |
| public List<int> List { get; set; } |
| } |
序列化
| using System.Xml.Serialization; |
| |
| void XmlSerilize(TestSerilize test) |
| { |
| using (var fs = new FileStream(Application.dataPath + "/test.xml", |
| FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite)) |
| |
| { |
| var sw = new StreamWriter(fs, System.Text.Encoding.UTF8); |
| var xml = new XmlSerializer(test.GetType()); |
| xml.Serialize(sw, test); |
| sw.Close(); |
| } |
| } |
反序列化
| using System.Xml.Serialization; |
| void XmlDeserialize() |
| { |
| using (var fs = new FileStream(Application.dataPath + "/test.xml", FileMode.Open, |
| FileAccess.Read, FileShare.Read)) |
| { |
| var xml = new XmlSerializer(typeof(TestSerilize)); |
| var data = (TestSerilize)xml.Deserialize(fs); |
| Debug.Log($"{data.Id} {data.Name} {data.List.Count}"); |
| |
| } |
| } |
# Binary
序列化
| using System.Runtime.Serialization.Formatters.Binary; |
| void BinarySerilize(TestSerilize test) |
| { |
| using (var fs = new FileStream(Application.dataPath + "/test.bytes", |
| FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite)) |
| { |
| var bf = new BinaryFormatter(); |
| bf.Serialize(fs, test); |
| } |
| } |
反序列化
| using System.Runtime.Serialization.Formatters.Binary; |
| void BinaryDeserilize() |
| { |
| using (var fs = new FileStream(Application.dataPath + "/test.bytes", |
| FileMode.Open, FileAccess.Read, FileShare.Read)) |
| { |
| var bf = new BinaryFormatter(); |
| var data = (TestSerilize)bf.Deserialize(fs); |
| Debug.Log($"{data.Id} {data.Name} {data.List.Count}"); |
| } |
| } |