- 积分
- 11687
- 明经币
- 个
- 注册时间
- 2015-8-18
- 在线时间
- 小时
- 威望
-
- 金钱
- 个
- 贡献
-
- 激情
-
|
本帖最后由 你有种再说一遍 于 2024-12-14 17:44 编辑
重修旧博文,让它C#入门最佳例子
https://www.cnblogs.com/JJBox/p/10850000.html
每次都凭借着新的经验去修改,
不过感觉新手很快就有看不懂的感觉了...
不过代码肯定是为了拿来运行的,不是教你们入门的...
我重新加入了一些新设计,
这个例子可以教会你反射/并行/线程安全结构/有序结构...
利用Linq并行,同时减少for的出现.
约束只反射当前dll程序集,排除了反射WPF程序集的错误,只反射公开类public部分.
双缓存机制,确保实例化和释放时处于同一个.
因为有两种加载时机,
所以埋入了文档事件,构建了多个加载时机的枚举,以及新的特性例子.
初始化反射写成源码生成器还挺困难的...
我看了net8.0的资料说type.GetMethods()这种是不能反射.
而是要指定函数名才行,泛型就不行.
讲讲Linq学习经验:
普通循环:
for(int j = 0; j < array.Length; j++;){
array[j].Run();
}
改写为Linq模式:
array = array.Select(a=>a.Run()).ToArray();
学习Linq尽可能要依赖链式调用,而不是返回值.
因为你总是会写这些任务:
数据源.过滤.映射.展开.过滤.排序.映射.ToList();
这个映射就是Select,它是一个数学概念
List<int> numbers = new List<int> { 1, 2, 3 };
var nums = numbers.Select(n => n * n).ToList();
由于Linq延迟执行:等到需要时候才进行遍历.
也就是末尾必须要ToArray/ToList.
因为延迟执行就是把代码写成"配置/使用"两个阶段,
你不ToList就还在配置阶段呀.
这机制有好处的,不会频繁构建中间数组.
Select处理每个元素时候,会把对象返回到集合,
那么Run方法要返回自己的类型,才可以被下一条链式调用识别.
如果Run方法是void的,那么需要:
array = array.Select(a=>{a.Run(); return a;}).ToArray();
不过我不喜欢这样的观感...
我会尽可能写一个有名函数来Linq语句调用.
Select它和ForEach区别,
就是一个需要返回值会构造集合,一个不需要.
不过通常这种微小损耗可以先不管.
array.ForEach(a=>a.Run());
改写PLinq并行模式,只需要增加两行:
array = array
.AsParallel() .WithDegreeOfParallelism(Environment.ProcessorCount)
.Select(a=>a.Run())
.ToArray();
同时划分了多线程并行区域和串行区域,
ToArray/ToList之后就是串行区域,大大降低了人们的心智负担.
也就是你可以写这样任务出来:并行-串行-并行-串行...
不过优化这样的任务就是尽可能一次并行剩余串行.
这个时候你可能会想,
它处理集合(数据源)是怎么分块进入不同线程的?
答案:
你大多数时候不需要管这个,反正它有自己的策略.
如果你觉得慢就把数据源手工切割分块和限制并行度就可以了.
什么时候会慢呢?
例如并行线程数的切换太多次,会频繁线程上下文切换,打断SIMD速度.则需要手工分块,把数据/核心数,然后每个线程跳跃到指定位置进行,每个线程之间不会交叉.
一个人建房子要10天,10个人只需要一天,
但是864000个人是不可能一秒建好房子的.
我们是要最佳的人数,某些没学过多线程编程的人就想几千个线程一起跑,殊不知有上下文切换的开销.
过滤条件的写法,
链式写法:
优点是可以插入条件方便,
缺点是大概率编译器不会合并它们,例如栈帧无法消除.
array = array.Where(a => a > 1)
.Where(a => a < 100)
.ToArray();
组合条件写法:
array = array.Where(a => a > 1 && a < 100).ToArray();
展开元素:
把多个数组合并到一起{{list1}{list2}}变成{list}
array = array.SelectMany(a=>a.GetList()).ToArray();
到处透露着简单又不失优雅的链式调用.
从第一次看到Linq真是完全看不懂,到如今可以靠手机敲代码.
要注意内存泄露哦:
http://bbs.mjtd.com/thread-191722-1-1.html
现代编程就是尽可能不写for,虽然它效率非常高,
但是满足例子最小化可以让人更好理解.
并且我们要相信编译器优化,
Linq展开之后是能够被优化,万一不行不也有热路径优化嘛.
不要在debug模式测试速度,要release模式测试.
for的本质就是集合操作,
写成下面需要比较多行,
但是只需要了解并集,差集之类的,就不用for了.
大家不要觉得是新瓶装旧酒,
万一别人内部写了循环展开呢,也比你直接写for快了.
var hashSet1 = new HashSet<int>() {1, 2, 3};
var hashSet2 = new HashSet<int>() {3, 4, 5};
hashSet1.UnionWith(hashSet2);
在JavaScript同类操作.
在SQL同类操作.
|
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?注册
x
|