C#高级编程5.0 读书笔记

写在前面

发现一个买实体书的好处吧,当你发现屋子里的乱七八糟的东西越来越多,想清理掉的时候,发现一堆没怎么翻过的书在那里,就只能把它看完,做好笔记再扔了。
这本书真的是比砖头还要厚,里面的各种知识点都很详细。但因为一些东西太过基础,一些东西又不是我想做的方向,所以我就对着目录圈出了自己觉得需要看的地方。下面做一个笔记,算是填充自己的资料库吧。
&& 发现里面有些东西有点旧了,但还是现看完再说,新添的特性再额外补充一下。

语法方面

  1. 关于两个main()函数:一般C#程序中,只允许有一个静态main函数作为入口,否则会编译错误。(看目录的时候还以为多个main函数可以有什么特殊操作特殊用法,结果并没有
  2. 闭包:声明匿名函数的时候,如果引用了匿名函数内部引用了外部的量,就会形成一个闭包。关于闭包,我个人理解就是匿名函数在实际执行的时候,会隐式创建一个类,这个类包含构造方法和一个与匿名函数相同的public方法,外部变量通过构造方法传到隐式类里面来,调用匿名函数时执行隐式类的public方法。了解了大致的原理,我们就可以知道,首先写程序的时候应该避免频繁使用带闭包的匿名函数;其次注意匿名函数中[[引用]]的外部变量,每次调用匿名函数,外部变量的值都是最新值,比如for循环中Dotween的OnComplete中输出循环变量 i 值,输出的 i 值不是从0开始,而是循环最大值这个高版本语言已经升级改掉了,不用在意这条,但低版本语言上还是有这个特性的,仍然需要注意
  3. 逆变和协变:协变out,逆变in。用在接口上,可以控制传参和返回值的类型大小。这地方确实比较绕。下面有个简单例子,帮助理解。其中A大于B表示A包含B,能用B的地方一定能用A。(一定要看注释)(个人觉得这个东西自然而然的就用出来了,死扣定义没什么大用,用多了就好了。&&写错了属于语法错误,有报错的,也不用怕出稀奇古怪的bug)
        /// 1. string 是 object 的子类 ==》 string < object
        /// 2. 作为输入值,能输入object的地方一定能输入string 
        ///   ==》 action<in string> 包含 action<in object> 
        ///   ==》 action<in string> 大于 action<in object>   
        ///    ==》 大小关系发生变化,为逆变
        /// 3. 作为输出值,能输出object的地方一定能输出string
        ///   ==> func<out object> 包含  func<out string>
        ///   ==> func<out string> 小于 func<out object> 
        ///   ==> 大小关系不变,为协变
        /// 4. 上面的2,3只是简单的举例,实际使用时,可以自己控制in,out参数
        
        Action<object> v = null;
        Action<string> c = v;

        Func<string> s = null;
        Func<object> d = ()=>
        {
            return s();
        };
  1. dynamic类型,可以在运行时确定变量的类型,而不是在编译阶段。但有两个限制,一个是动态类型不支持扩展方法,另一个是动态类型不能作为匿名函数的参数。个人觉得,dynamic在反射之类的东西里面会比较有用,平时一般开发中,基本不会用上这个东西。&&C#本身并不是动态语言,为了实现这个动态语言的功能,C#内部做了很多很多的操作,这也就导致了一个问题,他的效率并不高。

字符串

  1. string类
    需要注意的是,string类方法的一系列操作,基本都是重新创建新字符串,进行一系列处理后再将旧字符串丢弃,新字符串返回。所以,一些长字符串操作不要用string,影响效率。另外,除了常用的字符串方法,比如format之类的,还有其他的字符串方法,可以简单实现我们的需求。遇到类似的问题要先记得查一下API,尽量不要直接自己上手写,一是非学习情况下造轮子没什么意义,二是自己造的轮子还不一定好用。

  2. 长字符串的处理:使用StringBuilder
    StringBuilder仅能够替换追加删除字符串中的文本,而且它的效率很高。
    StringBuilder在能够设置Capacity,也就是操作字符串的空间大小。所有对字符串的操作都在这个空间中进行,而不用额外去申请内存空间,从而提高操作字符串的效率。在默认不设置Capacity的情况下,StringBuilder创建的空间会比初始化所用的字符串大,&&如果操作的字符超出所设置的Capacity,一般会自动翻倍。
    值得额外注意⚠️的是,只有对字符串频繁进行操作,才能获得StringBuilder的性能优势。

  3. 关于Fromat
    需要额外知道的就是通过实现IFormattable接口,可以自定义format格式。下面是一个简单的例子:

public class A : IFormattable
{
    public string content;
   
    public string ToString(string format, IFormatProvider formatProvider)
    {
        switch (format)
        {
            case "UP":
                return content.ToUpper();
                break;
            case "LOW":
                return content.ToLower();
                break;
            default:
                return content;
                break;
        }    
    }
}
var a = new A();
a.content = "Hello World !!!";

print($"{a:LOW}");
print(a.ToString("UP", null));
  1. 正则表达式
    关键字 Regex
    常用的正则表达式关键字.png

内存管理和指针

  1. 堆和栈
    1. 栈:存储值类型数据
    2. 托管堆:存储引用类型数据
  2. C#中的指针
    1. 在C#中使用指针需要添加unsafe标记
    2. 在类型后面添加*表示对应类型的指针。eg. int* byte*[]
    3. &取地址操作;*获取地址内容操作
  3. sizeof确定各种数据类型所占的空间大小(字节数)
  4. stackalloc分配一定大小的内存。下面是一个高速数组的例子:(需要注意的是,这种数据是没有越界报错的,需要自己额外检查)
unsafe static void Test()
{
    int* intArray = stackalloc int[10];
    for (int i = 0; i < 10; i++)
    {
        intArray[i] = i;
    }
    
    for (int i = 0; i < 10; i++)
    {
        Console.WriteLine(*(intArray + i));
    }
}

反射

  1. 这个东西游戏开发代码中一般是用不到的。其他的.net具体是什么样子就不清楚了,没有做过.net的正式商业项目,只是自己写过demo工具之类。欢迎大佬告知。
  2. 其实就是用名字来找对应的类型方法属性等等,然后对其进行动态创建调用方法等操作。
  3. 个人的使用感受:根据名字=》找程序集=》找类型=》找方法属性字段等等。找到你想找的量进行操作就好了。
    但这个名字有时候容易写不对。就Unity来说,Unity自己的非编辑器C#脚本是打在一个dll里面的,写编辑器工具时,不好直接填那个dll的名字。我当时是找了一个非编辑器类,用这个类取它所在的程序集,然后用获取到的这个程序集进行反射,来找其他的想要的类。算是一个偷懒的办法吧。

异步

  1. 最最基本的,使用Thread实现。这个没什么太需要注意的。需要注意一下的就是启动新线程消耗会比较大,要避免频繁创建线程。&&C#提供了其他的异步类和接口,这个可以基本不用了。
  2. Task,下面是几种创建&&启动方式。类&接口知道了,其他的细节需要的时候直接查一下就好了,这里不再记录。
创建

Task.Factory.StartNew

Task.Run

Task task1 = new Task(() =>
{
    Console.WriteLine(123);
});
task1.Start();
阻塞等待,当然还有其他的接口,用的时候直接看补全提示就好了
Task.WaitAll(task1)
  1. CancellationTokenSource 取消常驻线程辅助类。
    它的主要作用就是标记量,但相比普通的boolint,使用方便&&有自带的触发回掉接口。
  2. async await,用法感觉上和协程的yield return差不多。
    class Program
    {
        static void Main(string[] args)
        {
            var content = Test1().Result;//这个属性是阻塞的
            Console.WriteLine(content);
        }

        static async Task<string> Test1()//这里返回值还可以是`Task` `void`
        {
            string path = "";
            FileStream fs = new FileStream(path, FileMode.Open);
            StreamReader sr = new StreamReader(fs);

            string content = await sr.ReadToEndAsync();//这里等待读取完成

            return content;
        }
    }
  1. 并行Parallel:注意并行不保证执行顺序
    Parallel有三个静态方法,分别是Invoke,For,Foreach
    1. Parallel.Invoke(params Action[] actions):能够同时执行参数中的方法。
    2. Parallel.For:多次执行一个方法。如果需要执行的次数大于当前任务线程的数量,则同时执行的方法数量为当前最大任务线程数,这一批次执行完毕再执行下一个批。ParallelLoopState对象的Break方法能够提前终止该次并行。
    Parallel.For(0, 40, (i, p) =>
    {
        string content = $"i:{i} taskId:{Task.CurrentId} ThreadId:    {Thread.CurrentThread.ManagedThreadId}";
        Console.WriteLine(content);
    
        Thread.Sleep(1000);
    });
    
    3.Parallel.Foreach:并行执行一个方法。第二个Action参数中,第一个为迭代的值,第二个是并行状态变量,第三个为迭代次数。
    string[] test = new[]
    {
        "Hello",
        "World",
        "HHH",
        "123",
        "456",
    };
    
    Parallel.ForEach(test, (a, p, i) =>
    {
        Console.WriteLine($"content:{a}, long:{i}");
    });
    
  2. System.Timer.Timer 计时器,延迟多长时间触发事件。
  3. 关于线程间数据同步,第一个原则就是能不同步就不同步。必须同步的,除了简单的使用lock,还有其他的Spinlock,Interlocked等(++i不是线程安全的)。

一个实用工具

使用ildasm工具进行代码分析(反编译)。


断断续续,看一点写一点拖了好久,终于吧想看的看完了。

最后感谢大神写的好文章
深入理解 C# 协变和逆变,给了我很大启发。
C# Task和async/await详解,介绍的很详细。

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

推荐阅读更多精彩内容