熬最晚的夜,养最朋克的生✨ 2024-06-23 学习, Linux, C# 暂无评论 #### 被vs2022折磨的一晚 > 很久以前试过用vs发布到dockerhub,今天想试一下是不是那么回事,突发奇想,想写一个小服务,但是服务器是Linux,无奈只会C#,这个是最折中的一个方法了,哎。 #### 发布到dockerhub有两种方式,.Net Sdk和docker desktop, > 一开始嫌弃dockerdesktop体积太大,相当于是个虚拟机了,想尝试.netSdk,发布不了,一开始我以为是没有科学上网的环境,后来发现不是(到现在也不知道为啥不行) 无奈下载了desktop #### docker desktop也有坑 > vs默认的生成的镜像的tag是不带用户名的,如:webapplication1,这样是push不了,需要改tag才可以。 `docker tag webapplication1:latest 52hzelegy/webapp1:20240623` 系统就会多一个镜像,再push这个镜像就可以了。 明天把这个测试的镜像搞得服务器里测下,可以的话就开始整活了,睡觉睡觉!!!
关于C#多线程和异步的一些事。 2024-03-30 学习, C# 暂无评论 ## 多线程(Thread)和异步(Task)的区别 > 多线程是实现异步操作的方式,在需要进行异步操作的地方,会放开当前主线程(不阻塞),IO、网络需要阻塞的延迟操作会在新的线程中执行,执行结果再同步到当前主线程,实现异步。 --- `Thread`和`Task`都可以实现异步 #### Thread > 真正意义上的线程,如果需要做一些轮询操作,可以在线程中`while(true){轮询}` ##### Thread.Sleep(时间) 让当前**线程** 阻塞当前线程多少时间,单位毫秒, 可以理解成在异步操作里的 `await Task.Delay(时间)` #### Task ★ > 可以理解成轻量级的`Thread`, Task可以被await,`Task`可以定义任务的返回值, ``` C# var tsk1 = Task.Run(() => { Console.WriteLine("等待五秒后"); Thread.Sleep(5000); //Task.Delay(5000) Console.WriteLine($"任务取消{source.Token.IsCancellationRequested}"); }); ``` - 注意事项 `Task.Delay(5000)` 返回值是一个Task,如果不await的话,是不阻塞的,起不到阻塞的作用,如果是有返回值的Task,可以用Task.Result获取返回值,但是当前线程会阻塞。 所以如果换成了`Task.Delay(5000)` 是不会等待的直接会执行下面 - 几乎所有的Task都可以传递cts.Token,用来取消任务,但是,需要注意的是,下面是错误写法(下次别这样写,很捞批) ``` C# var tsk1 = Task.Run(() => { Console.WriteLine("等待五秒后"); Thread.Sleep(5000); //Task.Delay(5000) Console.WriteLine($"任务取消{source.Token.IsCancellationRequested}"); }, cts.Token); ``` 上面的`cts.Token`没有意义,不会对当前的Task生效,需要手动处理 `await Task.Delay(5000,cts.Token)` 如果超时,这行会抛出任务取消的异常,因为里面有封装过。 这种写法是可以取消任务的 ``` C# public async void ctsCancel(CancellationToken token) { try { //直接Run 可以运行,但是发生异常不会进入catch var tsk1 = Task.Run(async () => { await testAction(token); }); //这里会把异常抛出,进入catch await tsk1; } catch (Exception ee) { Console.WriteLine(ee.Message); } } //方法体 private Task testAction(CancellationToken cancellationToken) { return Task.Run(async () => { var ls = Enumerable.Range(1, 100).ToList(); foreach (var item in ls) { cancellationToken.ThrowIfCancellationRequested(); Console.WriteLine(item); await Task.Delay(500); } }); } ``` > token在外部已经进行超时处理了,五秒后会取消, `cancellationToken.ThrowIfCancellationRequested();`自己写的异步方法需要把token传过来,进行判断。 #### Task.ContinueWith() 类似于Js的Then 回调函数 > 这是Task对象的一个方法,可以传一个参数(Action),两个参数(Action,执行条件) 执行条件的是一个枚举,可以点进去看,根据上一步的状态(报错、执行完成),判断是否往下执行。 TaskContinuationOptions.OnlyOnRanToCompletion ``` C# public void ContinueWith() { var tsk = Task.Run(() => { Console.WriteLine("第一层"); Thread.Sleep(1000); Console.WriteLine("第一层等待一秒后"); var num = new Random().Next(1, 20); if (num % 2 == 0) { return num.ToString(); } else { throw new Exception("奇数异常"); } }).ContinueWith(r => { //如果上一个流程有异常,这里是不会执行的,异常也捕捉不到。 Console.WriteLine($"r.Exception==null : {r.Exception == null}"); Console.WriteLine("第二层"); var res = r.Result; return res; }, TaskContinuationOptions.OnlyOnRanToCompletion); try { //这里可以把异常抛出 var res = tsk.Result; Console.WriteLine("任务成功" + res); } catch (Exception ee) { Console.WriteLine("任务取消" + ee.InnerException?.Message); } } ``` #### 小结 > Task.Result和await Task 可以理解成把异步执行的结果拿到当前线程来,如果不拿过来的话,结果、异常都是没办法知晓的,因为不在同一个线程。 所以,在使用Task时候,可以在内部处理可能遇到的异常,多个Task可以用ContinueWith给串起来,在串起来的过程中可以配置往下执行的条件。
他又开始了,他说他会学的。😒😒😒 2024-01-02 默认分类, 学习, C# 暂无评论 > 起草了一个Erp的项目,立项的初衷是给俺姐用的,但是这可能是个商机,小公司不需要大型Erp,而且价格还贵,或者可以做起来搞个副业。 ##### 采用前后端分离的模式 1. 后端用的.Net6的WebApi框架,尽量的按照主流要求来 2. 前端打算使用Vue3来开发(好像你很熟一样🤣)只做微信小程序 3. 主要功能就是进销存功能,数据统计,财务报表管理等等,对这个也不熟,仅有的知识进行了头脑风暴 ##### 使用拦截器(过滤器) > 对数据进行严格的处理,注释写满!!保证低耦合、可维护性。 ##### 使用依赖注入 > 进一步降低代码的耦合,对定制系统可以更加友好,降低工作量。 ##### 最后 **一定要坚持下去!!!**
关于自己被C#类型转换伤害这件事~~~ 2022-03-25 学习, C# 暂无评论 > 报文都是用的byte发送的 byte的范围是0~255,也就是0x00~0xff, 1. 把字符串转换成byte - 需要先把字符串转换成整型 - 再把整型转换成byte - 要注意的是整型转换成byte的大小不能大于0xff 2. 代码 - `Convert.ToInt32("字符串",16) `16指的是16进制 - `BitConverter.GetBytes(charsint)[0]` 这个方法会生成数组,如果整型小于0xff那么第一个就是转换后的值,大于255的话,第二位就会进1, > 其实主要是把字符类型以16进制转换成整型,接下来就好操作了。
C# 委托和事件 2021-08-20 C# 暂无评论 ``` c# public delegate void SayHello(string content, string who);//定义委托(决定了参数类型和个数) public static event SayHello sayHelloEvent;//定义SayHello类型的事件 ``` ```c# SayHello dlgSay = say; //定义sayhelllo委托变量,并且绑定一个方法 dlgSay += say1; //给变量再增加一个方法 dlgSay("你好呀", "张三!"); //调用委托变量 这时候say和say1都会执行 SayHello dlgSay1 = delegate (string con, string name) { Console.WriteLine(name + con + "匿名函数"); }; //直接给委托变量绑定一个匿名函数 dlgSay1("nihao", "zhangsan"); SayHello dlg2 = (name, who) => { Console.WriteLine(name + who + "lambda"); };//绑定lambda表达式也可以 dlg2("你好,", "张三"); sayHelloEvent += Program_sayHelloEvent1; //注册事件 sayHelloEvent += Program_sayHelloEvent;//注册事件 //sayHelloEvent -= Program_sayHelloEvent; //注销事件 sayHelloEvent("事件", "事件1");//触发事件 ``` ```c# public static void say(string content, string who) { Console.Write($"{who}" + $"{content}"); } public static void say1(string content, string who) { Console.Write($"{who}" + $"{content}" + "say1"); } //触发事件的时候要执行的方法前提是已经次绑定了 private static void Program_sayHelloEvent1(string content, string who) { //原本应该是他先执行的(确实是先执行的)因为是异步延迟不妨碍后面的事件。 Task.Run(() => { Thread.Sleep(5000); Console.WriteLine(who + content + "我是被触发的事件 Program_sayHelloEvent1"); }); } private static void Program_sayHelloEvent(string content, string who) { Console.WriteLine(who + content + "我是被触发的事件 Program_sayHelloEvent"); } ``` tips: > 个人理解:委托(确定参数类型和个数)可以把方法给串起来,当这个委托变量被执行的时候会按照+=顺序来执行。 事件也是这么回事跟委托差不多,事件是用event修饰的委托,事件执行的时候,也是按照+=的顺序来执行方法(参数类型、个数、静态取决于委托是怎么定义的)