关于c#:改进你的c代码的5个技巧二

在本文中,我将向你展现c#编程的5个最佳实际。我从日常编程教训中学到了这些实际。我在release模式下测试了所有的代码,并在开发环境稳固后进行了截屏。我想你会喜爱这些倡议的。 在应用数据类型之前抉择它对于许多类型,咱们宁愿不决定在日常编程生存中应用什么数据类型。就在几个月前,我也是其中之一。然而当我开始学习编程中的最佳实际以进步代码性能时,我理解到了谬误的数据类型是如何影响代码的。我将展现一个演示来证实这个概念。 static void Main(string[] args) { List<Int32> li = new List<int>(); Stopwatch sw =new Stopwatch(); sw.Start(); for (int i = 0; i < 10000; i++) { li.Add(i); } sw.Stop(); Console.Write("Using Arraylist(Object)" + sw.ElapsedTicks + "n"); sw.Reset(); sw.Start(); Int32[] a = new Int32[10000]; for (int i = 0; i < 10000; i++) { a[i] = i; } sw.Stop(); Console.Write("Using Value(Integer Array)" + sw.ElapsedTicks); Console.ReadLine(); } 在下面的代码中,首先我应用了一个list来存储1000个整数值,在第二次执行雷同的操作时,我应用了一个整数数组。我的输入截图显示了哪种存储机制最适宜整数数组。当初,你可能会想为什么这个list要花更多的工夫呢?起因是,list以对象格局存储数据,当咱们首先尝试存储值类型时,它将其转换为援用类型,而后再存储。因而,第一点是始终抉择适当的存储机制以获得最佳性能。 ...

January 6, 2021 · 2 min · jiezi

关于c#:改进你的c代码的5个技巧一

敬爱的读者,在这篇文章中,我提供了一些c#编程的最佳实际。 你是否在用户输出验证中应用异样解决机制?如果是,那么你就是那个把你的我的项目执行速度升高了62倍的人。你不置信我吗?等几分钟;我来教你怎么做。然而在这个例子之前,让咱们理解一下在什么中央须要异样解决。 例如,你正在验证用户的数据,对于任何有效的输出,你将引发一个异样并将其抛出给客户端,如下所示: ; "复制代码") class BusinessLogcCheck { public void Check() { try { //Your validation code is here } catch (Exception ex) { throw new Exception("My own exception"); } } } ; "复制代码")  敬爱的敌人,在下一个示例中,如果你看到输入屏幕,你将意识到这种做法有多蹩脚。让咱们看看上面的代码。 ; "复制代码") using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Diagnostics; using System.IO; using System.Net; using System.Net.NetworkInformation; namespace Test1 { class Program { public static void ThrowTest() { throw new Exception("This is exceptopn"); } public static Boolean Return() { return false; } static void Main(string[] args) { Stopwatch sw = new Stopwatch(); sw.Start(); try { ThrowTest(); } catch { } sw.Stop(); Console.WriteLine("With Exception " + sw.ElapsedTicks); sw.Restart(); try { Return(); } catch { } sw.Stop(); Console.WriteLine("With Return " + sw.ElapsedTicks); Console.ReadLine(); } } } ...

January 5, 2021 · 3 min · jiezi

关于c#:在大型软件项目中如何处理错误和异常

我在测试中没有发现bug,所以零碎没有bug,对吧? 可怜的是,大规模的软件太简单,无论多少测试都无奈做到没有bug。你无奈对用户应用应用程序的所有不同形式进行测试。因而,了解应用程序中谬误和异样的区别是十分重要的,同时要理解解决它们的正确办法,以便你能够采取被动的形式为开发团队和终端用户提供衰弱的应用程序。 测试的局限性即便应用最彻底的测试过程,依然只是在测试特定的状况,并且蕴含了本人的想法在其中。 设想一下,忽然有成千上万的用户以你没有想到的形式应用你的应用程序——他们简直必定会碰到你在测试时没有碰到的货色。 如何正确处理应用程序中的谬误简略地说,bug能够导致谬误和异样。谬误和异样是有不同含意的术语。 次要的问题应该是如何更好地解决这些谬误和异样,使它们不会产生负面结果。 首先,让咱们看看一些定义,以及为什么这些区别很重要。 谬误和异样——有什么区别?一些编程语言有它们本人的谬误和异样定义,然而我想定义它们的区别。 谬误 无奈优雅地复原/持续的编程谬误,通常须要开发人员染指并批改代码来进行修复。有时能够将谬误转换为异样,以便在代码中解决它们。 通过简略查看能够防止谬误,如果简略查看不能满足要求,谬误还能够转化为异样,以便应用程序可能优雅地解决这种状况。 异样 利用特定语言的语义,并在产生异样时示意。异样能够被捕捉和抛出,以便代码能够复原和解决这种状况,而不进入谬误状态。 能够抛出和捕捉异样,以便应用程序可能失常复原或持续。还能够记录未解决的异样(即谬误),以便开发人员查看它们以修复底层谬误。 示例# 1 用户谬误——用户输出谬误数据,也不须要异样解决,但仍可能导致谬误/不可复原状态。代码应该进行简略的查看,以避免产生这种状况。应该应用前端和后端验证,对于本例,只抛出一个异样作为“最初的进攻”。 示例# 2 文件无奈关上并抛出FileLoadException或FileNotFoundException。这是一种非凡状况,不应该毁坏应用程序。应用程序应该可能解决这种状况,因为这种状况可能因为许多起因而产生,因而,你必须预期到这种状况。 该出错的还是会出错……至多一次“所以……如果我捕捉到每个异样,我的代码就不会出错了,对吧?” 正如我后面提到的,并非所有谬误都会导致异样。这个论断的次要问题是你不晓得哪里出了问题。你的代码可能存在许多问题,因为捕捉异样而对其不做任何解决,你会失落这些信息。 不要只是捕获每个异样,而后持续,就像什么都没有产生过一样。捕捉块的目标是在肯定状况下进行解决。 不要做什么——把他们捕捉起来。 如何编写应用程序来复原本人抛出和捕捉异样是让应用程序自行复原并避免它运行到谬误状态的好办法。 如果你晓得可能会抛出哪一种类型的异样,最好在catch块中显式地显示,因为每种不同类型的异样都将意味着代码因为不同的起因而进行。 异样类型要具体,这样就能够向用户提供反馈,并在确切晓得失败的起因后更优雅地解决其余状况。 为什么指定要捕获哪种类型的异样很重要?某些异样可能毁坏数据或以意外的形式运行,这取决于你的程序如何持续运行。这将导致应用程序呈现谬误。 如果你确切地晓得产生了哪种异样,那么你应该晓得要依照哪些步骤进行复原。或者,如果无奈复原,你应该晓得如何优雅地解决这种状况。 那么,它能复原吗?在很多状况下,异样具备足够的信息来晓得产生了什么谬误,并且在catch块中,你有时能够从谬误状态中复原。能够通过修复一些数据、从新获取数据或甚至要求用户再试一次。 你能够捕捉异样,但有时应用程序依然无奈持续运行,因为它所依赖的数据曾经以不可复原的形式被损坏,或者它冀望数据采纳不同的格局。 示例 数组上的OutOfRangeException异样?一个程序如何能力复原?这是一个将谬误转化为异样的例子。你的应用程序冀望数据以某种形式呈现,但这并没有产生。尽管复原并不总是可能,但当初可能不进入谬误状态并优雅地解决这种状况。如果将此记录下来,开发人员能够通过在拜访数组之前增加一些简略的查看或更改拜访它的形式来修复此问题。 如何解决未解决的异样有一些你意想不到的异样,通常示意代码中的谬误。你能够记录那些没有被代码捕捉的未解决的异样,因为大多数语言都提供了这样做的办法。任何未解决的异样都示意谬误。你的代码没有预料到这一点,因而无奈失常复原或解决这种状况。 将它们记录下来是一个好主见,这样就能够修复。这样,谬误就不会常常抛出异样。如果它们真的产生了,你想要理解它们,这样你就能够捕捉它们并解决它们。 谬误日志谬误日志能够帮忙捕捉这些谬误。有一个能够查看这些日志谬误/异样的中央是调试的要害,也是确定何时修复什么问题的优先级。 此外,你也不心愿依赖于屏幕截图和曾经丧气的用户提供的更多信息。谬误日志记录还能够使你的团队在呈现谬误时可能积极主动地分割受影响的用户。这是为了让他们晓得你正在解决问题,这不仅会促成你的客户关系,而且你还能够在其余用户遇到谬误之前修复谬误。 示例 代码中产生多个不正确的账单费用的谬误通常比无奈显示特定详细信息页面的谬误更重要,即便详细信息页面谬误产生得更频繁。 最终,你心愿应用程序遇到的异样尽可能少,然而当它遇到异样时,你心愿理解它。只有1%的用户报告谬误,所以还有很多谬误依然存在。 解决局部问题编写一些代码将异样和堆栈保留到文件中,或者通过电子邮件发送,以便在产生谬误时失去告诉,这可能是局部解决方案。 示例 一个用户会遇到上千个异样。100个用户也遇到了较少产生的谬误。哪个更重要?在不晓得谬误细节的状况下,影响更多用户的谬误更重要。 应用异样的堆栈应该有助于定位谬误可能呈现的地位,并且你应该可能从新生成它或浏览代码以了解那里出了错。 有时这还不够,问题须要进一步考察。如果产生这种状况,在记录异样之前向异样增加更多信息,包含上下文特定细节(例如帐户id或特定对象状态),这些信息将容许你在本地从新生成谬误。 是时候修改谬误了当初,你应该曾经捕捉了所有的谬误和异样,并记录未解决的谬误……当初该怎么办呢? 依据应用程序的规模,谬误告诉中的乐音是一个问题。你能够应用电子邮件过滤/grep做一些聪慧的事件,它能够分组谬误并拆散到不同的文件夹/文件中。这可能有所帮忙,但只是对乐音问题的局部解决方案。 几年前,我集体也这么做过,但很快意识到这只是一个局部的解决方案,起因有很多。问题是,我依然不晓得哪些谬误对用户的影响最大。我关注的是那些抛出的谬误,而不是那些对应用程序/用户体验最无害的谬误——正因为如此,我从未真正分明地晓得哪里出了问题。 我无奈看到产生了什么,但必须运行手动查问能力弄清楚,这十分耗时。 对于大型软件,总是会抛出谬误和异样。正确地处理错误将有助于将你定义为一个软件团队,并围绕异样和谬误创立更好的过程。 好的应用程序蕴含能够在可能的状况下从异样中复原的代码。解决和记录异样对软件的运行状况十分重要!  欢送关注我的公众号,如果你有喜爱的外文技术文章,能够通过公众号留言举荐给我。

January 5, 2021 · 1 min · jiezi

关于c#:c调用jar包的方法超详细

@前言: 最近我的项目遇到一个问题,就是有一个需要是cs端数据须要加密(应用sm4的加密办法),后端接管须要解密,然而cs端是c#写的 后端是java写的,两端的加密形式 的后果都会有所不同,当然还是咱们这帮菜逼对算法这块钻研不深。前面找了调用两头的c语言去弄 还是没有搞好,最初找的了一种办法,就是把java代码打成jar包 而后转换成dll,供cs端调用。步骤 一、将曾经编译后的java中Class文件进行打包;打包命令JAR打包:能够应用命令 也能够应用eclipse 和idea 这样的工具间接打包 【源码会放在最初】二、到IKVM官方网站下载IKVM须要的组件 http://www.ikvm.net/ 网上有一大堆教程 有很多没有提到jdk版本跟这个有关系,如图所示的反对1.8版本的,这个不向低版本兼容哦,如果找不到这个版本的ikvm能够私聊我。 三、设置门路解压ikvm-8.1.5717.0.zip,能够设置IKVM_HOME的门路到环境变量,也能够间接应用固定的门路配置进去,我这里是 间接把残缺的门路配置进去的 四、将java的jar包转换为.dll控件应用的命令:ikvmc -target:library xxx.jar 和 ikvmc -target:library -reference:需援用A.dll -reference:需援用B.dll 主的.jar前者命令是把jar打成dll 后者是把jar打成dll的同时 退出他须要内部引入的dll包(原jar包援用) ps:我这边是把jar包都复制到ikvm的bin目录下 ,并且在bin的目录下应用的ikvmc命令,如果是应用idea引入的是把所有的lib包放在一个目录下 在modules引入的,只须要把主jar包打成一个dll就行了 其余不用援用到cs外面去,elipse则是都须要打成dll 都引入。【这里是看理论状况而言,最好是都打成dll引入】五、在C#我的项目中增加所需的控件#### 前提须要下载:ikvm,不然会报错 #### 援用打包好的dll 当初就能够应用了 java源码地址:https://gitee.com/ten-ken/sec... 本文来源于:程序员ken,专属平台有csdn、思否(SegmentFault)、 简书、 开源中国(oschina)、掘金,转载请注明出处。

January 4, 2021 · 1 min · jiezi

关于c#:改进你的c代码的5个技巧一

敬爱的读者,在这篇文章中,我提供了一些c#编程的最佳实际。 你是否在用户输出验证中应用异样解决机制?如果是,那么你就是那个把你的我的项目执行速度升高了62倍的人。你不置信我吗?等几分钟;我来教你怎么做。然而在这个例子之前,让咱们理解一下在什么中央须要异样解决。 例如,你正在验证用户的数据,对于任何有效的输出,你将引发一个异样并将其抛出给客户端,如下所示: class BusinessLogcCheck { public void Check() { try { //Your validation code is here } catch (Exception ex) { throw new Exception("My own exception"); } } }  敬爱的敌人,在下一个示例中,如果你看到输入屏幕,你将意识到这种做法有多蹩脚。让咱们看看上面的代码。 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Diagnostics; using System.IO; using System.Net; using System.Net.NetworkInformation; namespace Test1 { class Program { public static void ThrowTest() { throw new Exception("This is exceptopn"); } public static Boolean Return() { return false; } static void Main(string[] args) { Stopwatch sw = new Stopwatch(); sw.Start(); try { ThrowTest(); } catch { } sw.Stop(); Console.WriteLine("With Exception " + sw.ElapsedTicks); sw.Restart(); try { Return(); } catch { } sw.Stop(); Console.WriteLine("With Return " + sw.ElapsedTicks); Console.ReadLine(); } } } 这就是你期待的输入。 ...

January 4, 2021 · 3 min · jiezi

关于c#:介绍一个新库-NornsUrdHttpClient

Norns.Urd.HttpClientNorns.Urd.HttpClient 基于AOP框架 Norns.Urd实现, 是对 System.Net.Http下的 HttpClient封装,让大家只需简略在接口定义就能够实现http的调用,能够缩小一些反复代码的书写。能够和已有的 Norns.Urd.Extensions.Polly 以及 Norns.Urd.Caching.Memory 配合应用。 源码放在:https://github.com/fs7744/Nor... 如何启用 HttpClient 性能引入Norns.Urd.HttpClientdotnet add package Norns.Urd.HttpClient代码中开启 HttpClient 性能,只需new ServiceCollection() .ConfigureAop(i => i.EnableHttpClient())定义 要应用的 HttpClient 接口举例如: [BaseAddress("http://localhost.:5000")]public interface ITestClient{ [Get("WeatherForecast/file")] [AcceptOctetStream] Task<Stream> DownloadAsync(); [Post("WeatherForecast/file")] [OctetStreamContentType] Task UpoladAsync([Body]Stream f);}注册到 ioc 中new ServiceCollection() .AddSingleton<ITestClient>() // 依照本人须要设置生命周期就好,并且不须要写具体实现,Norns.Urd.HttpClient会为您生成对应IL代码 .ConfigureAop(i => i.EnableHttpClient())通过DI 应用就好, 比方[ApiController][Route("[controller]")]public class ClientController : ControllerBase{ private readonly ITestClient client; public ClientController(ITestClient client) { this.client = client; } [HttpGet("download")] public async Task<object> DownloadAsync() { using var r = new StreamReader(await client.DownloadAsync()); return await r.ReadToEndAsync(); }}HttpClient反对的性能Url 配置BaseAddress如果有些网站域名或者根底api地址都是很多接口都会应用的,就能够在接口上应用 BaseAddressAttribute ...

January 3, 2021 · 2 min · jiezi

关于c#:Python-入门系列-6-数据类型

在编程语言中,数据类型是十分重要的概念,变量能够寄存不同类型的数据,并且不同的类型能够做不同的事件。 Python 领有上面这些数据类型,分类如下: 文本类型:string数字类型:int, float, complex序列类型:list, tuple, range字典类型:dict汇合类型:set, frozenset布尔类型:bool字节类型:bytes, bytearray, memoryview获取数据类型能够通过 type() 获取任何一个对象的类型。 x = 5print(type(x))--- output ---PS E:\dream\markdown\python> & "C:/Program Files (x86)/Python/python.exe" e:/dream/markdown/python/app/app.py<class 'int'>设置类型当你将一个值赋给一个变量的时候,数据类型列举如下: 设置指定的类型如果你想强制指定数据类型,能够应用上面列举的 函数的构造函数。 译文链接: https://www.w3schools.com/pyt...更多高质量干货:参见我的 GitHub: python

January 3, 2021 · 1 min · jiezi

关于c#:AOP的姿势之-简化混用-MemoryCache-和-DistributedCache-的方式

0. 前言之前写了几篇文章介绍了一些AOP的常识,然而还没有亮进去AOP的姿态,兴许姿态丑陋一点,大家会对AOP有点趣味内容大抵会分为如下几篇:(毕竟人懒,一下子写完太累了,没有能源) AOP的姿态之 简化 MemoryCache 应用形式AOP的姿态之 简化混用 MemoryCache 和 DistributedCache 应用形式AOP的姿态之 如何把 HttpClient 变为申明式至于AOP框架在这儿示例仍然会应用我本人基于emit实现的动静代理AOP框架: https://github.com/fs7744/Nor...毕竟是本人写的,魔改/加性能都很不便,万一万一大家如果有疑难,(尽管大略不会有),我也好答复, (当然如果大家认可,在github给个star,就切实是太让人开心了) 1. 十分重要的注意事项本篇次要目标是介绍如何利用AOP简化应用Cache的代码的形式然而在实在业务场景如果要混用 MemoryCache 和 DistributedCache,最好贴合场景好好思考一下,为何要这样用?每多加一个cache就是减少一层复杂度,如果一层cache不能解决问题?那么两层就能吗?三层就能吗?特地是缓存穿透等等怎么办呢?一层不能解决问题的起因是什么呢?心愿大家三思而行,哈哈 2. 如何混用呢?2.1 对立模型,对立接口MemoryCache 和 DistributedCache 的接口定义尽管类似度和思维很靠近,然而呢,还是存在不一样,大家能够看上面的接口定义 public interface IMemoryCache : IDisposable { // // 摘要: // Create or overwrite an entry in the cache. // // 参数: // key: // An object identifying the entry. // // 返回后果: // The newly created Microsoft.Extensions.Caching.Memory.ICacheEntry instance. ICacheEntry CreateEntry(object key); // // 摘要: // Removes the object associated with the given key. // // 参数: // key: // An object identifying the entry. void Remove(object key); // // 摘要: // Gets the item associated with this key if present. // // 参数: // key: // An object identifying the requested entry. // // value: // The located value or null. // // 返回后果: // true if the key was found. bool TryGetValue(object key, out object value); } public interface IDistributedCache { // // 摘要: // Gets a value with the given key. // // 参数: // key: // A string identifying the requested value. // // 返回后果: // The located value or null. byte[] Get(string key); // // 摘要: // Gets a value with the given key. // // 参数: // key: // A string identifying the requested value. // // token: // Optional. The System.Threading.CancellationToken used to propagate notifications // that the operation should be canceled. // // 返回后果: // The System.Threading.Tasks.Task that represents the asynchronous operation, containing // the located value or null. Task<byte[]> GetAsync(string key, CancellationToken token = default); // // 摘要: // Refreshes a value in the cache based on its key, resetting its sliding expiration // timeout (if any). // // 参数: // key: // A string identifying the requested value. void Refresh(string key); // // 摘要: // Refreshes a value in the cache based on its key, resetting its sliding expiration // timeout (if any). // // 参数: // key: // A string identifying the requested value. // // token: // Optional. The System.Threading.CancellationToken used to propagate notifications // that the operation should be canceled. // // 返回后果: // The System.Threading.Tasks.Task that represents the asynchronous operation. Task RefreshAsync(string key, CancellationToken token = default); // // 摘要: // Removes the value with the given key. // // 参数: // key: // A string identifying the requested value. void Remove(string key); // // 摘要: // Removes the value with the given key. // // 参数: // key: // A string identifying the requested value. // // token: // Optional. The System.Threading.CancellationToken used to propagate notifications // that the operation should be canceled. // // 返回后果: // The System.Threading.Tasks.Task that represents the asynchronous operation. Task RemoveAsync(string key, CancellationToken token = default); // // 摘要: // Sets a value with the given key. // // 参数: // key: // A string identifying the requested value. // // value: // The value to set in the cache. // // options: // The cache options for the value. void Set(string key, byte[] value, DistributedCacheEntryOptions options); // // 摘要: // Sets the value with the given key. // // 参数: // key: // A string identifying the requested value. // // value: // The value to set in the cache. // // options: // The cache options for the value. // // token: // Optional. The System.Threading.CancellationToken used to propagate notifications // that the operation should be canceled. // // 返回后果: // The System.Threading.Tasks.Task that represents the asynchronous operation. Task SetAsync(string key, byte[] value, DistributedCacheEntryOptions options, CancellationToken token = default); }那么咱们为了让多个不同实现的缓存接口能被同一段缓存操作代码所应用,就须要定义对立的接口并适配各种不同的缓存接口(当然,咱们不这样做也能凑出代码达到雷同成果,然而呢,他人看到这样的实现,难免会吐槽咱们的代码,如果不小心听见,体面有点挂不住呀)这里呢,咱们就这样简略定义一个这样的接口 ...

January 3, 2021 · 6 min · jiezi

关于c#:WPF-构建动画

写在后面:本文代码摘自《Head First C#》 本文应用ObjectAnimationUsingKeyFrames + Storyboard构建一个动画。 ObjectAnimationUsingKeyFrames为关键帧动画,它容许为动画设置几个关键帧,其中每一帧为ObjectKeyFrame类型。ObjectKeyFrame为抽象类,理论应用的是DiscreteObjectKeyFrame,它是ObjectKeyFrame的派生类,示意指标是不间断变动的。ObjectAnimationUsingKeyFrames的KeyFrames属性即为关键帧汇合。DiscreteObjectKeyFrame的Value属性为该帧的值,KeyTime属性为该帧的工夫点信息。 Storyboard可执行一组动画,上面的示例代码只蕴含一个动画。其SetTarget办法指定执行动画的界面元素,SetTargetProperty办法指定该动画利用到该界面元素的哪个属性上。定义并设置好动画后,将动画增加到Storyboard的Children中。 RepeatBehavior属性示意动画的反复行为。取值为0代表不播放,取其它double值管制循环次数,取RepeatBehavior.Forever示意始终循环。AutoReverse属性示意是否以相同的动画形式从终止值返回起始值。 // 前台,UserControl标记的代码<Grid> <Image x:Name="iamge" Streach="Fill" /></Grid>// 后盾代码public sealed partial class AnimatedImage:UserControl{ // 应用xaml创立控件,必须有一个无参构造函数 public AnimatedImage() { this.InitializeComponent(); } publi AnimatedImage(IEnumerable<string> imageNames, TimeSpan interval) :this() { StartAnimation(imageNames, interval); } public void StartAnimation(IEnumerable<string> imageNames, TimeSpan interval) { Storyboard storyboard = new Storyboard(); ObjectAnimationUsingKeyFrames animation = new ObjectAnimationUsingKeyFrames(); storyboard.SetTarget(animation, image); storyboard.SetTargetProperty(animation, "Source"); TimeSpan currentInterval = TimeSpan.FromMilliseconds(0); foreach(string imageName in imageNames) { ObjectKeyFrame keyFrame = new DiscreteObjectKeyFrame(); keyFrame.Value = CreateImageFromAssets(imageName); keyFrame.KeyTime = currentInterval; animation.KeyFrames.Add(keyFrame); currentInterval = currentInterval.Add(interval); } storyboard.RepeatBehavior = RepeatBehavior.Forever; storyboard.AutoReverse = true; storyboard.Children.Add(animation); storyboard.Begin(); } private static BitmapImage CreateImageFromAssets(string imageFilename) { return new BitmapImage(new Uri("ms=appx:///Assets/" + imageFilename)); }}

January 3, 2021 · 1 min · jiezi

关于c#:在-Emit-代码中如何await一个异步方法

0. 前言首先立马解释一波为啥会有这样一篇伪题目的Demo随笔呢?不是自己有常识误区,或者要误人子弟因为大家都晓得emit写进去的都是同步办法,不可能await,至多当初这么多年来没有提供对应的性能这是之前某天在微信群看见探讨怎么emit一个异步办法并包装异步构造,简略几句文字也未能清晰的表白所以趁着元旦节放假有点工夫,简略列举三种我晓得形式去达到这样的成果三种办法都是绕过emit间接书写emit代码,而是将对应逻辑转到其余办法中,最初emit调用办法达到成果 Demo 阐明原始办法是个提早2秒之后返回55的办法: public static async Task<int> GetV() { await Task.Delay(2000); return 55; }当初咱们须要把 55 的后果加 6 ,让最终的后果变为 61 咱们的测试方法是这样,会输入一些简略的工夫,帮忙咱们理解执行程序和异步状况 private static async Task Test(MethodInfo method, MethodInfo awaitMehtod) { var caller = CreateCaller(method, awaitMehtod); Console.WriteLine($"Start {awaitMehtod.Name} at: {DateTime.Now}."); var task = caller(); Console.WriteLine($"Call done at: {DateTime.Now}."); var number = await task; Console.WriteLine($"Hello {number} at: {DateTime.Now}."); Console.WriteLine($"End at: {DateTime.Now}."); Console.WriteLine(); }1. ContinueWith public static Func<Task<int>> CreateCaller(MethodInfo method, MethodInfo awaitMehtod) { var m = new DynamicMethod(Guid.NewGuid().ToString("N"), typeof(Task<int>), Type.EmptyTypes); var il = m.GetILGenerator(); il.Emit(OpCodes.Call, method); il.Emit(OpCodes.Call, typeof(Program).GetMethod(nameof(Program.AddSixUseContinueWith))); // 这里是差别点 il.Emit(OpCodes.Ret); return m.CreateDelegate(typeof(Func<Task<int>>)) as Func<Task<int>>; } public static Task<int> AddSixUseContinueWith(Task<int> task) { return task.ContinueWith(i => { Console.WriteLine($"AddSixUseContinueWith is: {DateTime.Now}."); return i.Result + 6; }); }测试后果:Start AddSixUseContinueWith at: 2021/1/2 13:34:55.Call done at: 2021/1/2 13:34:55.AddSixUseContinueWith is: 2021/1/2 13:34:57.Hello 61 at: 2021/1/2 13:34:57.End at: 2021/1/2 13:34:57.长处还是真正的异步 ...

January 2, 2021 · 2 min · jiezi

关于c#:如何在-AspNet-Core-实现-Excel-导出功能

在web利用程序开发时,或者你会遇到这样的需要,如何在 Asp.Net Core 中实现 excel 或者 word 的导入导出,在 NuGet 上有大量的工具包能够实现这样的性能,本篇就探讨下如何应用 ClosedXML 实现 Excel 数据导出。 装置 ClosedXML如果想实现 Excel 的导出性能,在 Asp.Net Core 中有很多的dll能够做到,其中的一个叫做 ClosedXML,你能够通过可视化界面 NuGet package manager 去装置,也能够应用命令行 NuGet package manager console 执行上面命令。 Install-Package ClosedXML将数据导出成 CSV 文件将数据导成 CSV 文件是非常简单的,毕竟每行数据都是用 , 隔开即可,能够用 NuGet 上的 CsvExport 或者 AWright18.SimpleCSVExporter 去实现,当然你感觉本人很 ????????,能够亲自操刀实现,上面我筹备亲自实现一下,先看上面定义的 Author 类。 public class Author{ public int Id { get; set; } public string FirstName { get; set; } public string LastName { get; set; }}而后塞一些数据到 authors 列表中,如下代码所示: ...

January 1, 2021 · 2 min · jiezi

关于c#:手把手叫你做一款音乐播放器csharp的winform

前言:我的项目是c#的winform 写的,应用的播放器是基于AxWindowsMediaPlayer。 AxWindowsMediaPlayer的办法 1.1 首先新建一个页面 如图所示: 图片左侧是列表 应用listview 右侧是背景图片。图片框框的中央是前面能够实现的,+和-按钮别离代表增加文件和删除文件 还有就是管制播放的程序。上面的别离是批改歌词的字体 和展现/暗藏 1.2 新建一个通明的歌词页面[窗体] 1.3 新建一个半透明的页面[窗体] 1.4 业务代码using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Text;using System.Windows.Forms;using WMPLib;using System.Media;using System.IO;using System.Text.RegularExpressions;using AxWMPLib;using System.Drawing.Drawing2D;using CCWin;namespace KenMusicPlayer{ public partial class MusicPlayer : Skin_DevExpress { public int index = 1; public int listIndex; private bool first_in = true; //是否第一次进入歌词区域 private bool showLrc = true;//默认显示歌词 private int imageInd = 0;//播放的图片下标 private List<string> imageList;//播放的图片 private Point closePoint;//敞开按钮的地位 private Size dfSize;//最后的地位 //声音 SoundPlayer player = new SoundPlayer(); Dictionary<string, string> dic = new Dictionary<string, string>(); //播放列表 Dictionary<string, IWMPMedia> playListDict = new Dictionary<string, IWMPMedia>(); List<string> al = new List<string>(); //以后歌词时间表 IWMPMedia media; /* *上面这一大段API调用,次要是用来设置歌词窗口的滚动条的 *但其实前面,我并没有怎么用到,只是在将滚动条滚动到底部时,用了一下 */ private const int WM_VSCROLL = 0x115; private const int SB_HORZ = 0; private const int SB_VERT = 1; private const int SB_CTL = 2; private const int SB_BOTH = 3; private const int SB_LINEUP = 0; private const int SB_LINELEFT = 0; private const int SB_LINEDOWN = 1; private const int SB_LINERIGHT = 1; private const int SB_PAGEUP = 2; private const int SB_PAGELEFT = 2; private const int SB_PAGEDOWN = 3; private const int SB_PAGERIGHT = 3; private const int SB_THUMBPOSITION = 4; private const int SB_THUMBTRACK = 5; private const int SB_TOP = 6; private const int SB_LEFT = 6; private const int SB_BOTTOM = 7; private const int SB_RIGHT = 7; private const int SB_ENDSCROLL = 8; private const int WM_PAINT = 0x000F; [System.Runtime.InteropServices.DllImport("user32.dll")] public static extern bool ScrollWindow(IntPtr hWnd, int XAmount, int YAmount, ref Rectangle lpRect, ref Rectangle lpClipRect); [System.Runtime.InteropServices.DllImport("user32.dll")] public static extern int SetScrollPos(IntPtr hwnd, int nBar, int nPos, bool bRedraw); [System.Runtime.InteropServices.DllImport("user32.dll")] public static extern int SetScrollPos(int nBar, int nPos, bool bRedraw); [System.Runtime.InteropServices.DllImport("user32.dll")] public static extern int GetScrollPos(IntPtr hwnd, int nBar); [System.Runtime.InteropServices.DllImport("user32.dll")] public static extern bool UpdateWindow(IntPtr hWnd); [System.Runtime.InteropServices.DllImport("user32.dll")] public static extern int SendMessage(IntPtr hwnd, int wMsg, int wParam, int lParam); public void setWord() { } public MusicPlayer() { this.StartPosition = FormStartPosition.CenterScreen;//窗口居中显示 InitializeComponent(); } private void MusicPlayer_Load(object sender, EventArgs e) { InitLoad(); } /// <summary> /// 初始化 加载播放列表 如歌词 背景图 定时器等等 /// </summary> private void InitLoad() { try { bool flag = false; string folder = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "bgImages"); DirectoryInfo root = new DirectoryInfo(folder); FileInfo[] files = root.GetFiles(); string fileName; for (int i = 0; i < files.Length; i++) { fileName = files[i].Name.ToLower(); if (fileName.EndsWith(".png") || fileName.EndsWith(".jpeg") || fileName.EndsWith(".jpg")) { if (!flag) { imageList = new List<string>(); this.pictureBox1.Image = Image.FromFile(files[i].FullName); } imageList.Add(files[i].FullName); flag = true; } } playerType.Text = playerType.Items[0].ToString();//默认第一个 closePoint = this.skinButtonClose.Location; dfSize = this.Size; richTextBox1.BackColor = this.TransparencyKey; skinComboBoxFontName.Text = skinComboBoxFontName.Items[0].ToString();//默认第一个 skinComboBoxFontSize.Text = skinComboBoxFontSize.Items[0].ToString();//默认第一个 ComboBoxSkinSelect.Text = ComboBoxSkinSelect.Items[0].ToString();//默认第一个 //this.BackPalace = Image.FromFile(ComboBoxSkinSelect.Items[0].ToString());//默认第一个 lvDetail.AllowDrop = true; lvDetail.View = View.Details; lvDetail.DragEnter += Files_DragEnter;//对象拖拽事件 lvDetail.DragDrop += Files_DragDrop;//拖拽操作实现事件 //wmp.OpenStateChange += WMP_OpenStateChange; wmp.PlayStateChange += WMP_PlayStateChange; timerImgs.Start(); } catch (Exception ex) { Console.WriteLine("谬误:" + ex.Message); } } /// <summary> /// 提供给通明歌词窗口的定时器调用的 /// </summary> /// <param name="s"></param> public void showTmform(bool s) { if (s) { this.btmForm.Show(); if (this.first_in) { this.lrcForm.TopMost = true; Point point = this.Location; point.Y = point.Y + this.Height; this.lrcForm.Location = point; this.btmForm.Location = point; this.lrcForm.Width = this.Width; this.btmForm.Width = this.Width; this.first_in = false; } } else { this.first_in = true; this.btmForm.Hide(); } } /// <summary> /// 播放时会进入这个事件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void WMP_PlayStateChange(object sender, _WMPOCXEvents_PlayStateChangeEvent e) { loadLrc(); } /// <summary> /// 拖拽操作实现事件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void Files_DragDrop(object sender, DragEventArgs e) { try { string fileName, fileExtension, fileSize, temp; FileInfo fi = null; ListViewItem lvi = null; Array array = (Array)e.Data.GetData(DataFormats.FileDrop); Regex regex = new Regex("(\\.mp3|\\.wav|\\.wma)"); string filePath; for (int i = 0; i < array.Length; i++) { filePath = array.GetValue(i).ToString(); //属于音乐文件 且列表中不存在 if (regex.IsMatch(filePath) && !dic.ContainsKey(filePath)) { wmp.Ctlcontrols.stop(); InsertPlayList(out fileName, out fileExtension, out fileSize, out temp, out fi, out lvi, filePath); } } } catch (Exception ex) { MessageBox.Show(ex.Message, "谬误", MessageBoxButtons.OK, MessageBoxIcon.Error); } } /// <summary> /// 插入播放列表 和字典集 /// </summary> /// <param name="fileName"></param> /// <param name="fileExtension"></param> /// <param name="fileSize"></param> /// <param name="temp"></param> /// <param name="fi"></param> /// <param name="lvi"></param> /// <param name="filePath"></param> private void InsertPlayList(out string fileName, out string fileExtension, out string fileSize, out string temp, out FileInfo fileInfo, out ListViewItem listViewItem, string filePath) { fileInfo = new FileInfo(filePath); temp = filePath.Remove(filePath.LastIndexOf('.')); fileName = Path.GetFileNameWithoutExtension(filePath); fileExtension = Path.GetExtension(filePath); fileSize = (fileInfo.Length / 1024).ToString() + "KB"; listViewItem = new ListViewItem(); listViewItem.Text = index++.ToString(); listViewItem.SubItems.AddRange(new string[] { fileName, fileExtension, fileSize, filePath }); lvDetail.Items.Add(listViewItem); //增加到播放列表 media = wmp.newMedia(filePath); //listIndex++, //wmp.currentPlaylist.insertItem(media); wmp.currentPlaylist.appendItem(media); playListDict.Add(filePath, media); //杜绝反复项 dic.Add(filePath, fileName); } /// <summary> /// 文件拖拽进入 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void Files_DragEnter(object sender, DragEventArgs e) { if (e.Data.GetDataPresent(DataFormats.FileDrop)) { e.Effect = DragDropEffects.Link; } else { e.Effect = DragDropEffects.None; } } /// <summary> /// 导入文件 /// </summary> private void tsmiLoading_Click(object sender, EventArgs e) { string fileName, fileExtension, fileSize, temp; FileInfo fi = null; ListViewItem lvi = null; openFileDialog1.Multiselect = true; openFileDialog1.Filter = "mp3文件(*.mp3)|*.mp3|wav文件(*.wav)|*.wav|wma文件(*.wma)|*.wma"; if (openFileDialog1.ShowDialog() == DialogResult.OK) { //程序播放 wmp.settings.setMode("shuffle", false); foreach (string filePath in openFileDialog1.FileNames) { if (!dic.ContainsKey(filePath)) { InsertPlayList(out fileName, out fileExtension, out fileSize, out temp, out fi, out lvi, filePath); } } } } /// <summary> /// 革除列表 /// </summary> private void ListViewClear_Click(object sender, EventArgs e) { lvDetail.Items.Clear(); } /// <summary> /// 播放 /// </summary> private void tsmiPlayer_Click(object sender, EventArgs e) { wmp.Ctlcontrols.play(); } /// <summary> /// 暂停 /// </summary> private void tsmiWaiting_Click(object sender, EventArgs e) { wmp.Ctlcontrols.pause(); } /// <summary> /// 进行 /// </summary> private void tsmiStop_Click(object sender, EventArgs e) { wmp.Ctlcontrols.stop(); } /// <summary> /// 退出 /// </summary> private void tsmiExit_Click(object sender, EventArgs e) { Application.Exit(); } /// <summary> /// 双击某项播放 /// </summary> private void lvDetail_DoubleClick(object sender, EventArgs e) { if (lvDetail.SelectedItems.Count > 0) { wmp.currentMedia = wmp.currentPlaylist.Item[int.Parse(lvDetail.SelectedItems[0].Text) - 1]; } } /// <summary> /// 循环播放 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void tsmiXunHuan_Click(object sender, EventArgs e) { //点击项 ToolStripMenuItem currentItem = (ToolStripMenuItem)sender; ToolStripItemCollection items = this.tsmiSet.DropDownItems; ToolStripMenuItem item; for (int i = 0; i < items.Count; i++) { item = (ToolStripMenuItem)items[i]; item.Checked = false; if (item.Name == currentItem.Name) { item.Checked = true; } } wmp.settings.setMode("loop", true); } //程序 private void tsmiDanQu_Click(object sender, EventArgs e) { IWMPMedia currentMedia = wmp.currentMedia; //点击项 ToolStripMenuItem currentItem = (ToolStripMenuItem)sender; ToolStripItemCollection items = this.tsmiSet.DropDownItems; ToolStripMenuItem item; for (int i = 0; i < items.Count; i++) { item = (ToolStripMenuItem)items[i]; item.Checked = false; if (item.Name == currentItem.Name) { item.Checked = true; } } //程序播放 wmp.settings.setMode("shuffle", false); } /// <summary> /// 图片宽高设置 /// </summary> /// <param name="imgToResize"></param> /// <param name="size"></param> /// <returns></returns> public static Image ResizeImage(Image imgToResize, Size size) { //获取图片宽度 int sourceWidth = imgToResize.Width; //获取图片高度 int sourceHeight = imgToResize.Height; float nPercent = 0; float nPercentW = 0; float nPercentH = 0; //计算宽度的缩放比例 nPercentW = ((float)size.Width / (float)sourceWidth); //计算高度的缩放比例 nPercentH = ((float)size.Height / (float)sourceHeight); if (nPercentH < nPercentW) nPercent = nPercentH; else nPercent = nPercentW; //冀望的宽度 int destWidth = (int)(sourceWidth * nPercent); //冀望的高度 int destHeight = (int)(sourceHeight * nPercent); Bitmap b = new Bitmap(destWidth, destHeight); Graphics g = Graphics.FromImage((System.Drawing.Image)b); g.InterpolationMode = InterpolationMode.HighQualityBicubic; //绘制图像 g.DrawImage(imgToResize, 0, 0, destWidth, destHeight); g.Dispose(); return (System.Drawing.Image)b; } private void playerType_SelectedIndexChanged(object sender, EventArgs e) { if (playerType.Text == "程序播放") { //程序播放 wmp.settings.setMode("shuffle", false); } else if (playerType.Text == "循环播放") { wmp.settings.setMode("loop", true); } else if (playerType.Text == "随机播放") { //程序播放 wmp.settings.setMode("shuffle", true); } } /// <summary> /// 定时器执行的办法,每隔1秒执行一次 歌词逐行显示 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void ShowLineLrc(object sender, EventArgs e) { this.label1.Text = this.wmp.Ctlcontrols.currentPositionString; if (this.lrcForm == null) { this.lrcForm = new TMForm(); Point pos = this.Location; pos.Y = lrcForm.Location.Y + lrcForm.Height; this.Location = pos; this.btmForm = new BTMForm(); MusicPlayer mainForm = (MusicPlayer)this.Owner; btmForm.Location = pos; this.lrcForm.Owner = this; this.btmForm.Owner = this; this.btmForm.Hide(); this.lrcForm.Show(); } if (this.wmp.currentMedia == null) { this.richTextBox1.Text = ""; return; } string durationString = this.wmp.currentMedia.durationString; int trackBarValue = Convert.ToInt32(this.wmp.Ctlcontrols.currentPosition); //this.trackBar1.Maximum = Convert.ToInt32(this.wmp.currentMedia.duration); //this.trackBar1.Value = Convert.ToInt32(this.wmp.Ctlcontrols.currentPosition); if (this.richTextBox1.Text != "歌词文件不存在" && this.richTextBox1.Text != "歌词文件内容为空") { int pos = al.IndexOf(trackBarValue.ToString()); bool isAr = this.richTextBox1.Text.Contains("歌手:"); bool isTi = this.richTextBox1.Text.Contains("歌名:"); if (pos >= 0) { int n = isAr ? 1 : 0; int m = isTi ? 1 : 0; int height = 28 * (this.al.Count + m + n); int max = height - this.richTextBox1.Height; this.richTextBox1.SelectAll(); this.richTextBox1.SelectionColor = Color.Black; this.richTextBox1.SelectionLength = 0;/**/ int l = this.richTextBox1.Lines[pos + m + n].Length; this.richTextBox1.Select(this.richTextBox1.GetFirstCharIndexFromLine(pos + m + n), l); this.richTextBox1.SelectionColor = Color.OrangeRed; this.richTextBox1.SelectionLength = 0; //this.Text = GetScrollPos(this.richTextBox1.Handle, SB_VERT).ToString() + "-" + al.Count + "-" + this.richTextBox1.Height; if ((pos + m + n) * 28 <= max) { int start = this.richTextBox1.GetFirstCharIndexFromLine(pos + m + n); this.richTextBox1.SelectionStart = start; this.richTextBox1.ScrollToCaret(); } else { //this.richTextBox1.Focus(); SendMessage(this.richTextBox1.Handle, WM_VSCROLL, SB_BOTTOM, 0); UpdateWindow(this.richTextBox1.Handle); //this.richTextBox1.SelectionStart = this.richTextBox1.Text.Length; //this.richTextBox1.ScrollToCaret(); } if (this.lrcForm != null) { string l1 = this.richTextBox1.Lines[pos + m + n]; string l2; if ((pos + m + n) < this.richTextBox1.Lines.Length - 1) { l2 = this.richTextBox1.Lines[pos + m + n + 1]; } else { l2 = "。。。。。"; } this.lrcForm.setLrc(l1, l2, pos); //this.lrcForm.setLrc(ArrayList al,); } } } //this.Text = this.trackBar1.Value.ToString(); /*if (trackBarValue >= (this.trackBar1.Maximum - 2)) { this.PlayModeChange(); }*/ } /// <summary> /// 载入歌词 /// </summary> /// <param name="lrc_filename">歌词路径名</param> public void loadLrc() { if (this.wmp.playState == WMPPlayState.wmppsPlaying) { IWMPMedia currentMedia = wmp.currentMedia; string fullPath = currentMedia.sourceURL; string geciPath = Path.Combine(Path.GetDirectoryName(fullPath), Path.GetFileNameWithoutExtension(fullPath) + ".lrc"); //播放哪个资源 列表需选中 ListView.ListViewItemCollection listViewItems = lvDetail.Items; lvDetail.FullRowSelect = true; for (int i = 0; i < listViewItems.Count; i++) { listViewItems[i].Checked = false; listViewItems[i].Selected = false; listViewItems[i].BackColor = Color.White; if (listViewItems[i].SubItems[4].Text == fullPath) { listViewItems[i].Checked = true; listViewItems[i].Selected = true; listViewItems[i].BackColor = Color.LightBlue; } } if (!File.Exists(geciPath)) { this.richTextBox1.Text = "歌词文件内容为空"; return; } using (StreamReader sr = new StreamReader(new FileStream(geciPath, FileMode.Open), Encoding.Default)) { string tempLrc = ""; while (!sr.EndOfStream) { tempLrc = sr.ReadToEnd(); } if (tempLrc.Trim() == "") { this.richTextBox1.Text = "歌词文件内容为空"; return; } tempLrc = tempLrc.Trim(); Regex rg = new Regex("\r*\n*\\[ver:(.*)\\]\r*\n*"); tempLrc = rg.Replace(tempLrc, ""); rg = new Regex("\r*\n*\\[al:(.*)\\]\r*\n*"); tempLrc = rg.Replace(tempLrc, ""); rg = new Regex("\r*\n*\\[by:(.*)\\]\r*\n*"); tempLrc = rg.Replace(tempLrc, ""); rg = new Regex("\r*\n*\\[offset:(.*)\\]\r*\n*"); tempLrc = rg.Replace(tempLrc, ""); rg = new Regex("\r*\n*\\[ar:(.*)\\]\r*\n*"); Match mtch; mtch = rg.Match(tempLrc); tempLrc = rg.Replace(tempLrc, "\n歌手:" + mtch.Groups[1].Value + "\n"); rg = new Regex("\r*\n*\\[ti:(.+?)\\]\r*\n*"); //这里留神贪心匹配问题.+? mtch = rg.Match(tempLrc); tempLrc = rg.Replace(tempLrc, "\n歌名:" + mtch.Groups[1].Value + "\n"); rg = new Regex("\r*\n*\\[[0-9][0-9]:[0-9][0-9].[0-9][0-9]\\]"); MatchCollection mc = rg.Matches(tempLrc); al.Clear(); foreach (Match m in mc) { string temp = m.Groups[0].Value; //this.Text += temp + "+"; string mi = temp.Substring(temp.IndexOf('[') + 1, 2); string se = temp.Substring(temp.IndexOf(':') + 1, 2); string ms = temp.Substring(temp.IndexOf('.') + 1, 2); //这是毫秒,其实我只准确到秒,毫秒前面并没有用 //this.Text += mi + ":" + se + "+"; string time = Convert.ToInt32(mi) * 60 + Convert.ToInt32(se) + ""; //这里并没有增加毫秒 al.Add(time); } tempLrc = rg.Replace(tempLrc, "\n"); char[] remove = { '\r', '\n', ' ' }; this.richTextBox1.Text = tempLrc.TrimStart(remove); this.timer1.Interval = 1000; this.timer1.Tick += ShowLineLrc; this.timer1.Start(); } } } private void wmp_Enter(object sender, EventArgs e) { loadLrc();//点击播放 } /// <summary> /// 删除选中的文件 并进行播放 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void skinButton2_Click(object sender, EventArgs e) { try { ListView.SelectedIndexCollection indexes = this.lvDetail.SelectedIndices; if (indexes.Count > 0) { int index = indexes[0]; string path = this.lvDetail.Items[index].SubItems[4].Text; IWMPPlaylist iWMPPlaylist = wmp.currentPlaylist; //先移除播放列表 再移除listview列表 wmp.currentPlaylist.removeItem(playListDict[path]); playListDict.Remove(path); this.lvDetail.Items[index].Remove(); dic.Remove(path); wmp.Ctlcontrols.stop(); } } catch (Exception ex) { MessageBox.Show("操作失败!\n" + ex.Message, "提醒", MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1); } } /// <summary> /// 列表鼠标双击事件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void lvDetail_MouseDoubleClick(object sender, MouseEventArgs e) { try { ListView.SelectedIndexCollection indexes = this.lvDetail.SelectedIndices; if (indexes.Count > 0) { int index = indexes[0]; string path = this.lvDetail.Items[index].SubItems[4].Text; wmp.Ctlcontrols.playItem(playListDict[path]); //wmp.URL = path;//这种形式会失去播放列表【不是肉眼可见的listview列表】 wmp.Ctlcontrols.stop(); wmp.Ctlcontrols.play(); } } catch (Exception ex) { MessageBox.Show("操作失败!\n" + ex.Message, "提醒", MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1); } } /// <summary> /// 字体扭转 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void skinComboBoxFontName_SelectedIndexChanged(object sender, EventArgs e) { if (this.lrcForm != null) { this.lrcForm.ChangeLabelFont(this.skinComboBoxFontName.SelectedItem.ToString(), this.skinComboBoxFontSize.SelectedItem.ToString()); } } /// <summary> /// 字体大小扭转 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void skinComboBox1_SelectedIndexChanged(object sender, EventArgs e) { if (this.lrcForm != null) { this.lrcForm.ChangeLabelFont(this.skinComboBoxFontName.SelectedItem.ToString(), this.skinComboBoxFontSize.SelectedItem.ToString()); } } /// <summary> /// 歌词是否显示 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void skinButton5_Click(object sender, EventArgs e) { if (this.lrcForm == null) { return; } this.showLrc = !this.showLrc; this.skinButton5.Text = this.showLrc ? "敞开" : "显示"; if (this.showLrc) { this.btmForm.Show(); this.lrcForm.Show(); } else { this.btmForm.Hide(); this.lrcForm.Hide(); } } /// <summary> /// 背景图片切换 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void timerImgs_Tick(object sender, EventArgs e) { if (imageInd <= imageList.Count - 2) { imageInd++; this.pictureBox1.Image.Dispose(); this.pictureBox1.Image = Image.FromFile(imageList[imageInd]); } else { imageInd=0; } } /// <summary> /// 粘贴音乐到播放列表 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void lvDetail_KeyDown(object sender, KeyEventArgs e) { System.Collections.Specialized.StringCollection stringCollection = Clipboard.GetFileDropList(); if (stringCollection != null) { string fileName, fileExtension, fileSize, temp; FileInfo fi = null; ListViewItem lvi = null; foreach (var item in stringCollection) { if ((item.ToLower().EndsWith(".mp3") || item.ToLower().EndsWith(".wav") || item.ToLower().EndsWith(".wma")) && !dic.ContainsKey(item) ) { InsertPlayList(out fileName, out fileExtension, out fileSize, out temp, out fi, out lvi, item); } } } } //抉择皮肤 private void ComboBoxSkinSelect_SelectedIndexChanged(object sender, EventArgs e) { string bgColor = ComboBoxSkinSelect.SelectedItem.ToString(); if (!string.IsNullOrEmpty(ComboBoxSkinSelect.SelectedItem.ToString())) { switch (bgColor) { case "突变黑": this.BorderPalace = kenMusicPlayer.Properties.Resources.bg_black; break; case "天蓝色": this.BorderPalace = kenMusicPlayer.Properties.Resources.bg_light_blue; break; case "墨绿色": this.BorderPalace = kenMusicPlayer.Properties.Resources.bg_green; break; case "蓝色": this.BorderPalace = kenMusicPlayer.Properties.Resources.bg_s_blue; break; case "浅灰色": this.BorderPalace = kenMusicPlayer.Properties.Resources.bg_grey; break; case "亮色": this.BorderPalace = kenMusicPlayer.Properties.Resources.bg_light; break; default: this.BorderPalace = kenMusicPlayer.Properties.Resources.bg_black; break; } /*this.UpdateStyles(); this.Update();*/ //this.BackPalace = Image.FromFile(ComboBoxSkinSelect.SelectedItem.ToString()); } } /// <summary> /// 退出 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void skinButtonClose_Click(object sender, EventArgs e) { //this.Close(); Application.Exit(); } private void MusicPlayer_Resize(object sender, EventArgs e) { try { Size size = this.Size; int x = (size.Width - dfSize.Width) + closePoint.X; int y = closePoint.Y;//(size.Height - dfSize.Height) + closePoint.Y; Point point = new Point(x, y); this.skinButtonClose.Location = point; } catch (Exception ex) { Console.WriteLine("异样:" + ex.Message); } } /// <summary> /// 改办法也是提供给通明歌词窗口用的,用来批改半透明窗体的地位,是通明歌词窗口和半透明窗体始终重合 /// </summary> /// <param name="pos"></param> public void moveTmform(Point pos) { this.btmForm.Location = pos; } }}源码地址:https://gitee.com/ten-ken/mus... ...

January 1, 2021 · 11 min · jiezi

关于c#:如何在-ASPNET-中使用-QuartzNET

当咱们在web开发中,经常会遇到这么一个需要,在后盾执行某一项具体的工作,具体的说就是这些工作必须在后盾定时执行。 Quartz.NET 是一个开源的 JAVA 移植版,它有着悠久的历史并且提供了弱小的 Cron 表达式,这篇咱们就来探讨如何在 ASP.NET Core 中应用 Quartz.NET 去执行一些后台任务。 装置 Quartz.NET要想应用 Quartz.NET,你能够应用 Visual Studio 2019 中的 NuGet package manager 可视化界面进行装置,或者通过 NuGet package manager console 命令行输出如下命令: Install-Package QuartzQuartz.NET 中的Job,triggers 和 SchedulersQuartz.NET 里有三个十分重要的概念:工作,触发器 和 调度器,对应着 Job,Trigger 和 Schedulers,Job 示意一个你须要被执行的工作,工作中能够写上你的业务逻辑代码,Job 就是一个实现了 IJob 接口的子类,如下代码所示: class Job : IJob { public Task Execute(IJobExecutionContext context) { throw new NotImplementedException(); } }Trigger 通常用于指定一个 job 是如何被调度的? 什么意思呢? 比如说:这个job是按天执行? 还是按小时执行?还是按秒执行?值得注意的是因为反对了 Cron 表达式,还可能实现更加超级简单的调度逻辑。 ...

January 1, 2021 · 3 min · jiezi

关于c#:如何在-ASPNET-Core-中实现全局异常拦截

异样是一种运行时谬误,当异样没有失去适当的解决,很可能会导致你的程序意外终止,这篇就来讨论一下如何在 ASP.Net Core MVC 中实现全局异样解决,我会用一些 样例代码 和 截图 来阐明这些概念。 全局异样解决其实在 ASP.Net Core MVC 框架中曾经有了全局异样解决的机制,你能够在一个中心化的中央应用 全局异样解决中间件 来进行异样拦挡,如果不必这种中心化形式的话,你就只能在 Controller 或者 Action 作用域上独自解决,这会导致异样解决代码零散在我的项目各处,不好保护也特地麻烦,不是吗? 第二种解决 全局异样 的做法就是应用 exception filter,在本篇中,我筹备跟大家聊一聊 全局异样解决中间件 和 UseExceptionHandler 办法来管控异样。 应用 UseExceptionHandler 扩大办法UseExceptionHandler 扩大办法可能将 ExceptionHandler 中间件注册到 Asp.net Core 的 申请解决管道 中,而后在 IExceptionHandlerFeature 接口的实例中获取 异样对象,上面的代码片段展现了如何应用 UseExceptionHandler 办法来截获全局异样。 public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { app.UseExceptionHandler(builder => { builder.Run(async context => { context.Response.StatusCode = (int)HttpStatusCode.InternalServerError; context.Response.ContentType = "application/json"; var exception = context.Features.Get<IExceptionHandlerFeature>(); if (exception != null) { var error = new ErrorMessage() { Stacktrace = exception.Error.StackTrace, Message = exception.Error.Message }; var errObj = JsonConvert.SerializeObject(error); await context.Response.WriteAsync(errObj).ConfigureAwait(false); } }); } ); app.UseStaticFiles(); app.UseRouting(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); }); }上面是代码中援用的 ErrorMessage 类的定义。 ...

January 1, 2021 · 2 min · jiezi

关于c#:如何在-AspNet-Core-中管理用户敏感数据

译文链接:https://www.infoworld.com/art...在利用程序开发时,你必定会有一些特地须要爱护的数据,这些数据通常是十分秘密的,敏感的,禁止和他人共享,这些信息包含:数据库连贯串,你懂的,毕竟外面有 userid 和 password,还有 OAuth 验证用到的 accesskey,apikey 或者配置 azure,aws 等云服务的连贯信息。 当我的项目和他人共享的时候,这些敏感信息天然也裸露给了他人,这通常是我不想看到的后果,那怎么去预防呢? ASP.NET Core 中有一个叫做 User Secrets 个性,它容许将用户敏感信息存储在我的项目外的一个 json 文件中,那怎么去治理这个 json 文件呢? 你能够通过 命令行工具 Secrets Manager 去进行敏感信息的治理,这篇文章次要就是来聊一聊怎么去治理这个 User Secrets。 在我的项目中增加 user secrets能够很不便的将 user secrets 增加到你的我的项目中,你须要做的仅仅是。 在解决方案管理器上抉择 project右键点击抉择 Manage User Secrets。 而后 Visual Studio 2019 会主动关上一个 secrets.json 文件。 接下来在 secrets.json 中增加一些敏感数据。 { "ConnectionString": "This is a test connection string", "APIKey": "This is s secret key", "AppSettings": { "GlobalSettings": { "GlobalAccessKey": "This is a global access key!" } }}对了, 默认的 secret.json 文件门路如下: ...

December 31, 2020 · 2 min · jiezi

关于c#:如何在-AspNet-Core-中对请求进行限流

译文链接:https://www.infoworld.com/art...在利用程序开发时,或者你有这样的想法,管制用户的申请频率来避免一些用户的歹意攻打,具体的说就是:为了预防有名的 拒绝服务 攻打,限度某一个ip在一段时间内的拜访次数,要解决这个问题,就要用到限流机制。 限流可能很好的管制住一个客户端拜访服务器资源地址的申请次数,在 asp.net core 之前,要实现限流机制,你可能要自定义 module 或者 handler,太繁琐了,不过很开心的是,在 asp.net core 里,能够很轻松的实现限流性能,这得益于 asp.net core 特有的 pipeline 机制,接下来,咱们一起钻研一下如何在 asp.net core 中实现限流机制。 装置 限流中间件为了可能实现限流性能,能够应用第三方提供的限流中间件,利用这个中间件给多个场景进行限流,比方:容许某一个 ip 或者 ip段 在指定的工夫周期内拜访某一个资源的次数,这个周期能够是:每秒,每分钟,每 n 分钟,等等。 在 Visual Studio 中创立好 ASP.NET Core API 之后,下一步就是装置 限流包 AspNetCoreRateLimit,你能够在 NuGet Package Manager 可视化工具上装置,也能够在 .NET CLI 命令行中装置,语句如下: dotnet add package AspNetCoreRateLimit如果想理解限流包 AspNetCoreRateLimit 的更多常识,参考 github: https://github.com/stefanprod... 配置 AspNetCoreRateLimit当初 AspNetCoreRateLimit 曾经援用到咱们我的项目中了,接下来在 ConfigureServices 办法中追加如下代码,最终将申请追加到 request-response pipeline 管道中。 public class Startup { // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddMvc().SetCompatibilityVersion (CompatibilityVersion.Version_2_2); services.AddOptions(); services.AddMemoryCache(); services.Configure<IpRateLimitOptions> (Configuration.GetSection("IpRateLimit")); services.AddSingleton<IIpPolicyStore, MemoryCacheIpPolicyStore>(); services.AddSingleton<IRateLimitCounterStore, MemoryCacheRateLimitCounterStore>(); services.AddSingleton<IRateLimitConfiguration, RateLimitConfiguration>(); services.AddHttpContextAccessor(); } }下面代码 Configuration.GetSection("IpRateLimit") 须要留神一下, 节点 IpRateLimit 的具体限流信息是配在 appsettings.json 中的。 ...

December 31, 2020 · 2 min · jiezi

关于c#:在-ASPNET-Core和Worker-Service中使用QuartzNet

当初有了一个官网包Quartz.Extensions.Hosting实现应用Quartz.Net运行后台任务,所以把Quartz.Net增加到ASP.NET Core或Worker Service要简略得多。 我将展现如何把Quartz.Net HostedService增加到你的利用,如何创立一个简略的IJob,以及如何注册它与trigger。 简介——什么是Quartz.NetQuartz.Net是一个功能齐全的开源作业调度零碎,能够在最小规模的应用程序到大型企业零碎应用。 有许多ASP.NET的钉子户,他们以一种牢靠的、集群的形式在定时器上运行后台任务。应用在ASP.NET Core中应用的Quartz.Net反对了.NET Standar 2.0,因而你能够轻松地在应用程序中应用它。 Quartz.Net有三个次要概念: job。这是你想要运行的后台任务。trigger。trigger管制job何时运行,通常按某种调度规定触发。scheduler。它负责协调job和trigger,依据trigger的要求执行job。ASP.NET Core很好地反对通过hosted services(托管服务)运行“后台任务”。当你的ASP.NET Core应用程序启动,托管服务也启动,并在应用程序的生命周期中在后盾运行。Quartz.Net 3.2.0通过Quartz.Extensions.Hosting引入了对该模式的间接反对。Quartz.Extensions.Hosting即能够用在ASP.NET Core应用程序,也能够用在基于“通用主机”的Worker Service。 尽管能够创立一个“定时”后盾服务(例如,每10分钟运行一个工作),但Quartz.NET提供了一个更加强壮的解决方案。通过应用Cron trigger,你能够确保工作只在一天的特定工夫(例如凌晨2:30)运行,或者只在特定的日子运行,或者这些工夫的任意组合运行。Quartz.Net还容许你以集群的形式运行应用程序的多个实例,以便在任何时候只有一个实例能够运行给定的工作。 Quartz.Net托管服务负责Quartz的调度。它将在应用程序的后盾运行,查看正在执行的触发器,并在必要时运行相干的作业。你须要配置调度程序,但不须要放心启动或进行它,IHostedService会为你治理。 在这篇文章中,我将展现创立Quartz.Net job的基础知识。并将其调度到托管服务中的定时器上运行。 装置Quartz.NetQuartz.Net是一个.NET Standar 2.0的NuGet包,所以它很容易装置在你的应用程序中。对于这个测试,我创立了一个Worker Service我的项目。你能够通过应用dotnet add package Quartz.Extensions.Hosting命令装置Quartz.Net托管包。如果你查看我的项目的.csproj,它应该是这样的: <Project Sdk="Microsoft.NET.Sdk.Worker"> <PropertyGroup> <TargetFramework>net5.0</TargetFramework> <UserSecretsId>dotnet-QuartzWorkerService-9D4BFFBE-BE06-4490-AE8B-8AF1466778FD</UserSecretsId> </PropertyGroup> <ItemGroup> <PackageReference Include="Microsoft.Extensions.Hosting" Version="5.0.0" /> <PackageReference Include="Quartz.Extensions.Hosting" Version="3.2.3" /> </ItemGroup></Project>这将增加托管服务包,从而引入Quartz.Net。接下来,咱们须要在应用程序中注册Quartz.Net的服务和 IHostedService。 增加Quartz.Net托管服务注册Quartz.Net须要做两件事: 注册Quartz.Net须要的DI容器服务。注册托管服务。在ASP.NET Core中,通常会在Startup.ConfigureServices()办法中实现这两项操作。Worker Services不应用Startup类,所以咱们在Program.cs中的IHostBuilder的ConfigureServices办法中注册它们: public class Program{ public static void Main(string[] args) { CreateHostBuilder(args).Build().Run(); } public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureServices((hostContext, services) => { // Add the required Quartz.NET services services.AddQuartz(q => { // Use a Scoped container to create jobs. I'll touch on this later q.UseMicrosoftDependencyInjectionScopedJobFactory(); }); // Add the Quartz.NET hosted service services.AddQuartzHostedService( q => q.WaitForJobsToComplete = true); // other config });}这里有几个乏味的点: ...

December 31, 2020 · 3 min · jiezi

关于c#:NET-5-源代码生成器MediatRCQRS

在这篇文章中,咱们将摸索如何应用.NET 5中的新source generator个性,应用MediatR库和CQRS模式主动为系统生成API。 中介者模式中介模式是在应用程序中解耦模块的一种形式。在基于web的应用程序中,它通常用于将前端与业务逻辑的解耦。 在.NET平台上,MediatR库是该模式最风行的实现之一。如下图所示,中介器充当所发送命令的发送方和接管方之间的中间人。发送者不晓得也不关怀谁在解决命令。  应用MediatR,咱们定义了一个command,它实现IRequest<T>接口,其中T示意返回类型。在这个例子中,咱们有一个CreateUser类,它将返回一个字符串给调用者: public class CreateUser : IRequest<string>{ public string id { get; set; } public string Name { get; set; }} 从ASP.NET Core API发送命令到MediatR,咱们能够应用以下代码: [Route("api/[controller]")][ApiController]public class CommandController : ControllerBase{ private readonly IMediator _mediator; public CommandController(IMediator mediator) { _mediator = mediator; } [HttpPost] public async Task<string> Get(CreateUser command) { return await _mediator.Send(command); }}在接收端,实现也非常简单:创立一个实现IRequestHandler<T,U>接口的类。在本例中,咱们有一个处理程序,它解决CreateUser并向调用者返回一个字符串: public class CommandHandlers : IRequestHandler<CreateUser, string="">{ public Task<string> Handle(CreateUser request, CancellationToken cancellationToken) { return Task.FromResult("User Created"); }}每个处理程序类能够解决多个命令。解决规定是对于一个特定的命令,应该总是只有一个处理程序。如果心愿将音讯发送给许多订阅者,则应该应用MediatR中的内置告诉性能,但在本例中咱们将不应用该性能。 ...

December 30, 2020 · 2 min · jiezi

关于c#:C中的依赖注入和IoC容器

在本文中,咱们将通过用C#重构一个非常简单的代码示例来解释依赖注入和IoC容器。  简介:依赖注入和IoC乍一看可能相当简单,但它们非常容易学习和了解。 在本文中,咱们将通过在C#中重构一个非常简单的代码示例来解释依赖注入和IoC容器。 要求:构建一个容许用户查看可用产品并按名称搜寻产品的应用程序。 第一次尝试:咱们将从创立分层架构开始。应用分层架构有多个益处,但咱们不会在本文中列出它们,因为咱们关注的是依赖注入。 上面是应用程序的类图: 首先,咱们将从创立一个Product类开始: public class Product{ public Guid Id { get; set; } public string Name { get; set; } public string Description { get; set; }}而后,咱们将创立数据拜访层: public class ProductDAL{ private readonly List<Product> _products; public ProductDAL() { _products = new List<Product> { new Product { Id = Guid.NewGuid(), Name= "iPhone 9", Description = "iPhone 9 mobile phone" }, new Product { Id = Guid.NewGuid(), Name= "iPhone X", Description = "iPhone X mobile phone" } }; } public IEnumerable<Product> GetProducts() { return _products; } public IEnumerable<Product> GetProducts(string name) { return _products .Where(p => p.Name.Contains(name)) .ToList(); }}而后,咱们将创立业务层: ...

December 29, 2020 · 3 min · jiezi

关于c#:用-Roslyn-做个-JIT-的-AOP

0. 前言上接:AOP有几种实现形式 接下来说说怎么做AOP的demo,先用csharp 说下动静编织和动态编织,有工夫再说点java的对应内容。 第一篇先说Roslyn 怎么做个JIT的AOP demo。 为啥这样讲呢? 理论是因为Roslyn 曾经蕴含了JIT的全副局部,那我也就不用说任何JIT的实现了。(真爽) 所以本篇理论说的是以下这些内容: 怎么引入Roslyn做JIT编译代码 代理模式的AOP是什么样 为什么不举荐在生产环境不做优化就这样玩? 1. JIT编译代码Roslyn 是.NET的编译器,感兴趣的能够参见文档 https://docs.microsoft.com/en... 实际上Roslyn曾经做的非常简单了,几行代码引入进来就能够编译csharp代码了。 不信咱们就手把手写一个 1.1 引入Roslyn包 <ItemGroup> <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.6.0" /> <PackageReference Include="System.Runtime.Loader" Version="4.3.0" /> </ItemGroup>1.2 代码转化为语法树public SyntaxTree ParseToSyntaxTree(string code){ var parseOptions = new CSharpParseOptions(LanguageVersion.Latest, preprocessorSymbols: new[] { "RELEASE" }); // 有许多其余配置项,最简略这些就能够了 return CSharpSyntaxTree.ParseText(code, parseOptions);}1.3 筹备编译器实例public CSharpCompilation BuildCompilation(SyntaxTree syntaxTree){ var compilationOptions = new CSharpCompilationOptions( concurrentBuild: true, metadataImportOptions: MetadataImportOptions.All, outputKind: OutputKind.DynamicallyLinkedLibrary, optimizationLevel: OptimizationLevel.Release, allowUnsafe: true, platform: Platform.AnyCpu, checkOverflow: false, assemblyIdentityComparer: DesktopAssemblyIdentityComparer.Default); // 有许多其余配置项,最简略这些就能够了 var references = AppDomain.CurrentDomain.GetAssemblies() .Where(i => !i.IsDynamic && !string.IsNullOrWhiteSpace(i.Location)) .Distinct() .Select(i => MetadataReference.CreateFromFile(i.Location)); // 获取编译时所需用到的dll, 这里咱们间接简略一点 copy 以后执行环境的 return CSharpCompilation.Create("code.cs", new SyntaxTree[] { syntaxTree }, references, compilationOptions);}1.4 编译到内存中public Assembly ComplieToAssembly(CSharpCompilation compilation){ using (var stream = new MemoryStream()) { var restult = compilation.Emit(stream); if (restult.Success) { stream.Seek(0, SeekOrigin.Begin); return AssemblyLoadContext.Default.LoadFromStream(stream); } else { throw new Exception(restult.Diagnostics.Select(i => i.ToString()).DefaultIfEmpty().Aggregate((i, j) => i + j)); } }}1.5 测试一下static void TestJIT(){ var code = @" public class HiJ { public void Test(string v) { System.Console.WriteLine($""Hi, {v}!""); } }"; var jit = new Jit(); var syntaxTree = jit.ParseToSyntaxTree(code); var compilation = jit.BuildCompilation(syntaxTree); var assembly = jit.ComplieToAssembly(compilation); // test foreach (var item in assembly.GetTypes()) { Console.WriteLine(item.FullName); item.GetMethod("Test").Invoke(Activator.CreateInstance(item), new object[] { "joker" }); }}运行后果: ...

December 28, 2020 · 3 min · jiezi

关于c#:C日志使用

本文参考链接 日志框架框架抉择:NLog 装置办法,Nuget命令行:Install-Package NLog 罕用规定尽量不要在循环中打印日志。应输入谬误的堆栈信息:e.Message仅为异样形容,e.ToString()能够打印异样堆栈。抛异样的中央不要打印日志,因为个别捕捉异样的中央会打印,屡次打印造成反复输入。日志级别的应用要精确。要害信息能够加显眼的符号,如程序启动时:======= app start =======,不便疾速定位信息。不要应用Console.WriteLine(),效率低。日志的放弃工夫应在15天以上重要日志适当缩短。配置日志框架输入格局的内容不要蕴含类名、函数名、行号等信息,这种行为耗费微小。审慎记录日志,防止输入大量有效日志、信息不全的日志。日志函数的参数不要应用拼接字符串,应用格式化字符串。应该打印什么日志调试日志:开发阶段应用大量调试日志,不便调试,上线后禁止。运行日志:记录程序的运行,该局部日志应能体现程序的运行流程。状态日志:记录程序的状态,用于数据展现。NLog性能简介NLog应用应用独自文件进行NLog配置,文件名命名为NLog.config配置autoReload="true":配置批改是否主动加载。配置throwExceptions="false":日志出现异常时是否须要抛出异样,若配置为true日志记录异样时因为没有捕捉异样,会导致程序挂掉。配置internalLogLevel=Debug:示意nlog日志的执行日志记录等级,开发过程中配置为Debug,上线后配置为Info。配置internalLogFile:示意nlog日志的执行日志记录的地位。通过./XXXX的形式能够配置到程序的绝对目录。日志一律保留到./Logs/日期/过程名.log日志级别应用范畴规定为Debug-Error,只容许应用这四个级别的日志。开发过程中将日志等级设为Debug,上线后设置为Info。配置targets的aasync=true:异步保留日志,从而避免日志影响业务性能。日志等级LevelFirstCharacterOrdinalTraceT0DebugD1InfoI2WarnW3ErrorE4FatalF5OffO6通过NLog.LogManager.GetLogger咱们能够获取一个日志对象示例。传入的参数为日志实例名,咱们能够在日志名中通过${logger}参数输入日志实例名。能够将不同的日志保留到不同的文件。 targets配置NLog通过target配置日志输出的指标。能够通过配置多个target将日志输出到多个目录,多个指标(文件,网络,数据库等)。如通过设置2个指标,将info和error日志离开保留。其中很多参数是共用的,咱们能够设置一个默认参数default-target-parameters,缩小配置文件节点。 xsi:type:输出类型: ColoredConsole : 应用可自定义的色彩将日志音讯写入控制台。Console - 将日志音讯写入控制台。Debug - 模仿指标-用于测试。File - 将日志音讯写入一个或多个文件。Mail - 应用 smtp 协定或拾取文件夹通过电子邮件发送日志邮件。Null - 抛弃日志音讯。次要用于调试和基准测试。name:指标的名字,能够通过创立Rule规定限度指标的输入。 filename:文件名,日志保留文件时能够保留到该文件中。文件名反对参数化,通过各种参数更不便的输入日志。 archiveFileName:为了避免日志文件保留的太大,咱们将日志文件拆分保留。通过archiveFileName参数设置保留格局,具体格局能够到这里查看。 createDirs:若设置的日志文件夹不存在,则主动创立文件夹。 keepFileOpen:为了进步文件写入性能,防止每次写入文件都开关文件,将keepFileOpen设置为true,咱们通过openFileCacheTimeout参数定时敞开文件。 autoFlush:为了进步日志写入性能,不用每次写入日志都间接写入到硬盘上,将autoFlush设置为false,咱们通过openFileFlushTimeout参数定时写入文件。 openFileCacheTimeout:将keepFileOpen参数设置为false,则设置定时敞开日志。避免日志始终开着占用着。 openFileFlushTimeout:将autoFlush参数设置为false,则设置定时将日志从缓存写入到硬盘工夫。 archiveAboveSize:为了避免一个文件日志太大,咱们须要依据指定大小将日志拆文件保留。archiveAboveSize参数的单位是字节。通过设置为10240=10KB,每个日志大小达到10KB就会主动拆分文件,拆分后的文件名规定通过archiveFileName设置,拆分文件名的规定通过archiveNumbering设置,具体规定能够查看这里。 concurrentWrites:反对多个并发一起写文件,进步文件写入性能。 encoding: Nlog默认保留的编码格局为Encoding.Default,中文保留到日志中会呈现乱码,将其设置为utf-8,就能够失常保留了。layout:示意输入的格局,若为最简略的内容输出,则间接通过参数设置输出格局即可。除了最简略的文本格式还反对以下四种类型的数据,通过xsi:type参数设置layout的格局,如xsi:type="JsonLayout": CSV - A specialized layout that renders CSV-formatted events.Compound - A layout containing one or more nested layouts.Log4JXml - A specialized layout that renders Log4j-compatible XML events.JSON - A specialized layout that renders to JSON. Json格局保留咱们须要在layout节点下减少attribute来减少字段。rules配置咱们能够创立一系列规定束缚输入的内容。办法是在NLog节点下增加rules节点,rules节点下能够增加多个logger节点,每个logger节点为一条束缚。 ...

December 27, 2020 · 1 min · jiezi

关于c#:C开发规范

写在后面:本文是依据alibaba的Java开发手册以及WPF源码整顿的一篇实用于C#的开发标准。 命名格调代码中的命名严禁应用拼音与英文混合的形式,更不容许间接应用中文的形式。命名空间、类名、办法、属性、事件、枚举、私有动态字段、常量应用UpperCamelCase格调。公有字段、参数名、局部变量应用lowerCamelCase格调,听从驼峰模式。异样类名应用Exception结尾,测试类名以要测试的类名结尾,Test结尾。防止在子父类的成员变量间、不同代码块的局部变量间采纳雷同的命名。杜绝不标准的缩写,要做到顾名思义。应用缩写时要是被广泛承受的缩写。为达到代码自解释的指标,命名时应尽量应用残缺的单词组合表白意思。在常量与变量命名时,示意类型的名称放在词尾:startTime, workQueue接口类中的办法和属性不要加任何润饰符号,加上无效的正文。接口类加I前缀。枚举类名不要加Enum后缀,枚举成员名称应用UpperCamelCase格调命名。用于事件处理的委托加EventHandler后缀,用于事件处理之外的委托加CallBack后缀。在变量名中应用互补对,如min/max、begin/end、open/close不要在事件申明中应用前缀或者后缀,如应应用Close而不是OnClose。如果变量值仅在一个固定范畴内变动,应用enum类型定义: public enum Season{ Spring, Summer, Autumn, Winter}用UI组件缩写做UI变量前缀,如:Label - lbl TextBox - tbox TextBlock - tblk Button - btn Image - img Grid - grd StackPanle - stkpnl代码格局若大括号内为空,简洁的写成{}即可,大括号两头无需换行和空格;如果非空代码块则左右大括号各占一行。左小括号和字符之间不呈现空格,右小括号和字符间也不要呈现空格。if/for/while/switch/do等保留字与括号之间必须加空格。任何二目、三目运算符的左右两边都须要加一个空格。采纳四个空格缩进,禁止应用tab,可在IDE中设置tab为4个空格。正文的双斜线与正文之间有且只有一个空格。在进行类型强制转换时,右括号与强制转换值之间不须要空格。单行字符数限度不超过120个,超出则换行,换行准则如下:1) 第二行绝对第一行缩进4个空格,从第三行开始,不再缩进;2) 运算符与下文一起换行;3) 办法调用的点符号与下文一起换行;4) 办法调用的多个参数换行时,在逗号后换行;5) 括号前不要换行 办法参数在定义和传入时,多个参数逗号后必须加空格。单个办法的总行数不超过80行。不须要增加若干个空格使变量的赋值等号与上一行对应地位的等号对齐。不同逻辑、不同语义、不同业务的代码之间插入一个空行分隔开以晋升可读性。以下状况下应用一个空行:a. 办法与办法,属性与属性之间;b. 办法中变量申明与语句之间;c. 办法中不同逻辑块之间;d. 办法中的返回语句与其余语句之间;e. 属性与办法,属性与字段,办法与字段之间; 任何情景下,不须要插入多个空行进行隔开。一行只做一个申明。倡议在变量申明时就对其做初始化。不要应用public的实例字段。每行一个语句。面向对象所有笼罩的办法,必须加override。内部正在应用的接口,不容许批改办法签名,防止对接口调用产生影响。构造函数中禁止退出任何业务逻辑,如果有初始化逻辑,请放在init办法中。一个类有多个构造方法,或多个同名办法时这些办法应该按程序放在一起,便于浏览。类内办法定义的程序:私有 > 爱护 > 公有。属性的get、set办法中,不要减少业务逻辑,减少排查问题的难度。慎用对象的Clone办法来拷贝对象,因为是浅拷贝,若想实现深拷贝需笼罩Clone办法。类成员与办法的拜访严格控制:1) 如果不容许内部间接通过new来创建对象,构造函数必须是private;2) 工具类不能有public构造方法;3) 类非static字段必须是private;4) 类static如果仅在本类应用,必须是private;5) 类办法如果仅供外部调用,必须是private;6) 类办法只对继承类公开,限度为protected。 不要给成员变量加任何前缀,辨别局部变量与成员变量应用this。类名与文件名保持一致。类型成员的排列程序:1) 委托、事件申明2) 公共动态、常量字段3) 构造函数,参数越少越靠前4) public办法5) 属性6) protected办法 -> private办法 -> internal办法7) 公有字段 ...

December 27, 2020 · 1 min · jiezi

关于c#:C面向对象引用类型和值类型

咱们学习了类和对象的基础知识过后,就能够来理解一些对象背地的常识了。 Student wx = new Student(); 这行代码,实际上做了三件事: 生成一个对象(new Student()),取得该对象的存储地址申明一个Student的变量wx将在1中生成的对象存储地址赋值给2中的变量wx,从而把变量wx和对象关联起来如图所示: 了解这三步十分重要。其关键点就在于:wx中存储的不是对象自身,而是对象的地址。在C#中,对象的地址又被称之为“援用”,所以但凡以这种模式寄存的类型,都被称之为 援用类型但凡由class申明的类型,都是援用类型;“指向”援用类型(寄存援用类型对象的地址)的变量,就被称之为援用类型变量。因为援用类型变量并不寄存实质性数据,所以当咱们运行这一行代码的时候: wx.age = 18; 18并没有寄存在wx中,而是寄存在wx(通过内存地址)所指向的对象中,如图所示: 同时留神,如果wx变量没有指向任何对象的话,咱们能够说它的值为null 。null值上不能进行任何运算,因为对象为null值而报的谬误NullReferenceException是程序中最常见的谬误。 Student wx = null; //运行就会报错:NullReferenceException Console.WriteLine(wx.Name); 和援用类型对应的,就是 值类型目前咱们曾经学习过的int,float,bool等都是值类型(string是一种十分非凡的援用类型,数组是援用类型)。值类型的特点就是: 变量寄存的不是地址,而是间接寄存“值”。比方: int i = 18; 变量i中间接寄存着18这个数值。如图所示: 值类型变量的值不能为null,如果没有为其赋值,它会有一个默认值(参考:默认值表)。 了解值类型和援用类型的区别有什么作用呢?咱们来看一下这两段代码: int i = 18; int j = i; -- 留神这一行代码 j = 20; Console.WriteLine(i); -- i的值是18还是20? 咱们留神赋值运算符(=),它意味着将=右侧的值赋值给左侧。那么 j=i ,就是把变量i的值赋值给变量j。而变量i的值是多少? 是整数18。这里的赋值,不是“挪动”(挪动的话i就没值了,^_^),而是“复制”,就是把i中的值18复制一份给j,让j里也寄存着18。 所以,再下一句,j=20,就又把20赋值给了j,但也仅仅是把20赋值给了j,不能影响i的值。 那么,再看看这个代码: Student wx = new Student(); wx.age = 18; Student clone = wx; -- 这里是把wx的什么赋值给了clone? clone.age = 20; Console.WriteLine(wx.age); ...

December 27, 2020 · 1 min · jiezi

关于c#:C面向对象枚举和位运算

大家在学习DateTime的时候有没有发现一个DayOfWeek类型,示意星期几。应用F12就能够看到它的定义: 这里就呈现了: 枚举(Enum)枚举(enum)是和类(class)、构造(struct)并列的一种类型。它的成员又被称之为枚举值,枚举值不能有任何修饰符,只能蕴含两局部: 名称,比方DayOfWeek中的Sunday、Monday等,名称个别是“有意义的”,以不便开发人员调用底层数据,比方DayOfWork中的0、1、2等。默认底层数据是int类型,还能够应用其余整数类型,比方byte、short等,如下所示:enum Grade : short //默认是int类型,当初是short类型 { } 底层数据也能够不写,不写的话默认从0开始,从上到下顺次减少1: enum Grade : short //默认是int类型 { Excellent, //不写底层数据默认为O Passed, //默认以1的步长递增底层数据 Failed = 8 //指定底层数据 } 枚举能够像类型一样应用: //申明Grade属性 public Grade grade { get; set; } //作为办法的返回值 static Grade GetBy(int score){} //作为办法的参数 static int GetBy(Grade score){} 它的值间接枚举名点(.)出即可: //申明变量/字段 Grade grade = Grade.Excellent; 因为枚举的整型底层数据,所以能够在枚举和整型之间进行强制转换: Console.WriteLine((short)Grade.Excellent); //int类型也行(能够和short转换) Console.WriteLine((int)Grade.Passed); Console.WriteLine((int)Grade.Failed); Console.WriteLine((Grade)0); //Excellent Console.WriteLine((Grade)16); //无奈转换时也不会报错,间接输入16 留神:枚举的默认值是: 0所对应的枚举值,或者如果找不到0所对应的枚举值,就间接为0演示: 为什么要应用枚举呢? 以DayOfWork为例,如果没有枚举,咱们如何传递“星期几”呢?比方咱们有一个办法,能够依据星期几返回bool值,如果是星期三和星期六,就返回true,示意当天不上课,^_^ 怎么申明这个办法呢?参数用什么类型?int,string?比方这样: static bool IsRest(int dayofWork) { return dayofWork == 3 || dayofWork == 6; } ...

December 27, 2020 · 2 min · jiezi

关于c#:C面向对象万物皆对象Object和装箱拆箱

咱们来看一下这个代码: DayOfWeek.Friday.GetType() DayOfWeek.Friday是一个枚举值,它的这个GetType()是哪里冒出来的?联合咱们后面所学的常识,子类中找不到的成员,肯定是来自于它的父类,是不是?然而,enum DayOfWeek又没有继承啊? 欲知详情,有一个简略粗犷的方法:间接在GetType()上F12,马上转到办法定义: 哈哈,GetType()就是 Object的实例办法嘛! 实际上,Object是C#中所有类型的父类,能够说它是万物之祖。因而,任何类默认主动的继承自Object,不须要显式申明。 Object还有其余几个罕用的办法: 1、Equals():留神这里有它是一个静态方法,用于比拟作为参数传入的两个对象: 如果是值类型,比拟两个对象的值内容(所有字段),雷同为true,否则为false如果是援用类型,如果有一个值是null值,返回false,否则当两个变量指向同一个对象,返回true;否则为falsestruct Bed //值类型 //class Bed //援用类型 { internal int Id { get; set; } } 检测代码: Bed a = new Bed(); a.Id = 1; Bed b = new Bed(); b.Id = 1; //或者=2 //如果Bed是struct,true //如果Bed是class,false Console.WriteLine(Equals(a, b)); 演示: 对于== 值类型:内置的简略值类型:比拟值自定义的值类型:默认不反对,须要本人进行运算符重载enum:比拟底层数值援用类型:同Equals(),除非进行了运算符重载string:相似于值类型,且两个为null/empty的字符串雷同2、GetHashCode():获取对象的哈希值。哈希(Hash),有被称之为散列,是一种获取固定长度数据的算法。GetHashCode()能够获取将以后对象进行Hash估算之后的后果。 留神:GetHashCode()是virtual的,所以能够被子类重写(override)。 如果没有被重写,两个完全相同的对象GetHashCode()的Hash值必然雷同。然而,雷同的Hash值并不意味着生成他们的对象雷同!所以,咱们能够用GetHashCode()确定两个对象不雷同,但不能用于确定他们雷同。 //接下面代码 ///Bed为值类型,输入相等 ///Bed为援用类型,输入不同 Console.WriteLine(a.GetHashCode()); Console.WriteLine(b.GetHashCode()); 演示: _3、GetType():获取以后对象的类型信息。留神这里获取的是以后对象的类型信息,不是以后变量的类型信息。什么意思呢?看代码:_ Person wx = new Student(); Console.WriteLine(wx.GetType().Name); //后果为:Student ...

December 27, 2020 · 1 min · jiezi

关于c#:C面向对象string还是StringBuilder

咱们之前成心对string一带而过,是因为它十分特地。首先,它是 imutable(不可变的)即一个string定义的字符串,一旦设定,就不能扭转。 在string上间接F12转到定义,就能够看到String类的成员。其中,只有一个只读的动态成员Empty(倡议应用,以代替null和空字符串""): public static readonly String Empty; 一个只读的索引器,能够获取字符串中某个下标的字符: public char this[int index] { get; } 一个只读的属性Length,能够获取字符串长度: public int Length { get; } 全部都是只读的,没有任何一个可写的类成员。再看看它的办法,有几个和“批改”相干的: string slagon = "@大神小班,拎包入住@"; //删除 Console.WriteLine(slagon.Remove(1)); //后果:@ Console.WriteLine(slagon.Remove(1, 1)); //后果:@神小班,拎包入住@ //插入 Console.WriteLine(slagon.Insert(2, "@")); //后果:@大@神小班,拎包入住@ //替换 Console.WriteLine(slagon.Replace('大', '小')); //后果:@小神小班,拎包入住@ //截取 Console.WriteLine(slagon.Substring(1, 3)); //后果:大神小 //留神:slagon还是没有变 Console.WriteLine(slagon); //后果:@大神小班,拎包入住@ 以及修剪掉字符串前后空白字符的Trim()办法: string fg = " 大 飞 哥 "; //应用一个@后缀显示成果 Console.WriteLine(fg.Trim() + "@"); //删除前后空白:大 飞 哥@ Console.WriteLine(fg.TrimStart() + "@"); //删除后面的空白:大 飞 哥 @ Console.WriteLine(fg.TrimEnd() + "@"); //删除前面的空白: 大 飞 哥@ //fg自身不会扭转 Console.WriteLine(fg + "@"); // 大 飞 哥 @ ...

December 27, 2020 · 2 min · jiezi

关于c#:C中的深度学习五在MLNET中使用预训练模型进行硬币识别

在本系列的最初,咱们将介绍另一种办法,即利用一个事后训练好的CNN来解决咱们始终在钻研的硬币辨认问题。 在这里,咱们看一下转移学习,调整预约义的CNN,并应用Model Builder训练咱们的硬币辨认模型。 咱们将应用ML.NET代替Keras.NET。为什么不应用Keras.NET呢?只管Keras.NET非常简单,易于学习,尽管它蕴含后面提到的预约义模型,但它的简略性使咱们无奈自定义CNN架构来适应咱们的问题。 ML.NET是一个微软的收费机器学习框架,旨在应用C#和F#进行开发。最重要的是,咱们能够将ML.NET与Azure联合应用,这意味着咱们能够应用基于云的基础设施来训练咱们的模型。让多个虚拟机以分布式形式运行咱们的代码能够使训练更快、更精确。 为什么预训练的CNN如此有价值?因为有人花了很多工夫和资源培训他们,咱们能够利用这一点。咱们能够重用嵌入在为网络计算的权值,咱们能够将它们从新利用到相似的问题中。也就是说,它们不仅能够利用于CNN最后训练解决的问题。这种办法就被称为迁徙学习。它能够为咱们节俭大量的培训工夫,并大大提高所取得的后果。 在迁徙学习中,咱们不像以前那样从零开始。相同,咱们从一个已知的模型开始,该模型具备预约义的体系结构和在第一次申请模型时下载的计算权重。风行的模型包含Inception、ResNet和VGG16等。 要针对咱们的问题调整预约义的CNN,咱们必须做三件事。首先,咱们必须将输出层的形态更改为数据集中图像的维度。其次,咱们至多须要更改输入层,以便模型领有与数据集雷同数量的类。第三,咱们必须调整模型,让它晓得咱们对训练预约义模型的层不感兴趣。 实现这些步骤后,咱们能够训练或使咱们的模型适宜于给定的数据集。 让咱们开始吧。在Visual Studio中,转到Extensions > Manage Extensions,浏览ML.NET Model Builder。咱们还须要装置Nuget包ML.NET。为了训练咱们的模型来解决硬币辨认问题,咱们将应用 Model Builder 扩大。应用这个工具,咱们能够轻松地设置数据集并训练模型,它通过 Model Builder中增加的Auto ML个性主动抉择模型。主动机器学习(automatic Machine Learning, Auto ML)是一种自动化机器学习模型开发中的耗时工作。所以Model Builder将为咱们简化筹备数据集的过程,以及抉择事后训练好的模型和所有波及的参数。对于所选的预训练模型,有一点是只有最初一层会被从新训练;其余所有人都放弃权重。 对于数据集的状况,惟一的要求是将其组织在文件夹中,这样文件夹名就是其中所有图像的类或标签。 当咱们到目前为止应用的硬币数据集被输出到模型构建器中时,AutoML引擎抉择ResNet作为事后训练好的架构来用于咱们的问题。一旦训练完结,咱们就能够预测新的输出数据,甚至能够失去与为预测而生成的模型绝对应的代码。只需这么少的工作,咱们就能够在简直没有任何相干常识的状况下应用ML,通过UI简略地实现所有工作,抉择、单击并在最初取得代码。 对于应用C#进行硬币辨认的系列文章到此结束。心愿你喜爱!如果有任何问题,不要遗记留言或发信息。感激你的浏览。 欢送关注我的公众号,如果你有喜爱的外文技术文章,能够通过公众号留言举荐给我。

December 25, 2020 · 1 min · jiezi

关于c#:C中的深度学习四使用KerasNET识别硬币

在本文中,咱们将钻研一个卷积神经网络来解决硬币辨认问题,并且咱们将在Keras.NET中实现一个卷积神经网络。 在这里,咱们将介绍卷积神经网络(CNN),并提出一个CNN的架构,咱们将训练它来辨认硬币。 什么是CNN?正如咱们在本系列的前一篇文章中提到的,CNN是一类常常用于图像分类工作的神经网络(NN),比方物体和人脸识别。在CNN中,并非每个节点都连贯到下一层的所有节点。这种局部连通性有助于避免在齐全连贯的网络神经网络中呈现的过拟合问题,并且减速了神经网络的收敛速度。 围绕CNN的外围概念是一种被称为卷积的数学运算,卷积在数字信号处理畛域十分常见。卷积被定义为两个函数的乘积,产生的第三个函数示意前两个函数之间的重叠量。 在物体辨认中,卷积操作容许咱们检测图像中的不同特色,如垂直和程度的边缘,纹理和曲线。这就是为什么任何CNN的第一层都是卷积层。 CNN中另一个常见的层是池化层。池化用于缩小图像示意的大小,这意味着缩小参数的数量,并最终缩小计算量。最常见的池化类型是最大池化,它在每个地位上从匹配的单元格组中获取最大值。最初,依据所取得的最大值建设新的图像。 另一个与卷积相干的概念是填充。填充保障了卷积过程将平均地产生在整个图像,包含边界像素。这个保障是由一个零像素的边框反对的,该边框在放大后的图像四周增加(在池化之后),以便能够以雷同的次数拜访图像的所有像素。 最常见的CNN架构通常从卷积层开始,接着是激活层,而后是池化层,最初是传统的全连贯网络,比方多层NN。这种类型的模型是层次化的,称为程序模型。为什么以一个齐全连贯的网络完结?为了学习转换后图像(通过卷积和池化)中的特色的非线性组合。 上面是咱们将在CNN中实现的架构: Conv2D层- 32个过滤器,过滤器大小为3激活层应用ReLU函数Conv2D层- 32个过滤器,过滤器大小为3激活层应用ReLU函数MaxPooling2D层-利用(2,2)池窗口DropOut图层,25% -通过随机删除前一层的一些值来避免过拟合(设置为0);也就是浓缩法Conv2D层- 64个过滤器,过滤器大小为3激活层应用ReLU函数Conv2D图层- 64个过滤器,过滤器大小为3,步幅为3激活层应用ReLU函数MaxPooling2D层-利用(2,2)池窗口DropOut层,25%Flatten层-转换数据,以在下一层中应用Dense 层——示意具备512个节点的传统神经网络的全连贯。激活层应用ReLU函数DropOut层,在50%Dense层,与节点数量匹配的类的数量Softmax层该体系结构遵循了一种用于物体辨认的CNN体系结构模式;层参数通过试验进行了微调。 咱们通过的参数微调过程的后果局部存储在Settings类中,咱们在这里展现: public class Settings{ public const int ImgWidth = 64; public const int ImgHeight = 64; public const int MaxValue = 255; public const int MinValue = 0; public const int Channels = 3; public const int BatchSize = 12; public const int Epochs = 10; public const int FullyConnectedNodes = 512; public const string LossFunction = "categorical_crossentropy"; public const string Accuracy = "accuracy"; public const string ActivationFunction = "relu"; public const string PaddingMode = "same"; public static StringOrInstance Optimizer = new RMSprop(lr: Lr, decay: Decay); private const float Lr = 0.0001f; private const float Decay = 1e-6f;}咱们当初有了CNN的体系结构。接下来,咱们将钻研应用Keras.NET实现的用于硬币辨认的CNN。 ...

December 24, 2020 · 2 min · jiezi

关于c#:面向对象程序设计Object-Oriented-Programming的三大特性六大原则

三大个性封装、继承、多态性拿简略工厂模式举例: namespace DesignMode_01{ // 计算基类 public class Operation { private double _numberA = 0; private double _numberB = 0; public double NumberA { get => _numberA; set => _numberA = value; } public double NumberB { get => _numberB; set => _numberB = value; } public virtual double GetResult() { double result = 0; return result; } } // 加法类 public class OperationAdd : Operation { public override double GetResult() { double result = 0; result = NumberA + NumberB; return result; } } // 减法类 public class OperationSub : Operation { public override double GetResult() { double result = 0; result = NumberA - NumberB; return result; } } // 工厂类:生产不同类的实例化对象 public class OperationFactory { public static Operation CreateOperate(string operate) { Operation oper = null; switch (operate) { case "+": oper = new OperationAdd(); break; case "-": oper = new OperationSub(); break; } return oper; } } // 当编译器遇到办法调用时,它首先在类型的实例办法中查找匹配项。如果找不到匹配项,它将搜寻为该类型定义的所有扩大办法,并绑定到找到的第一个扩大办法。 public static class MyExtensions { public static int Count(this String str) { return str.Split(new char[] { ' ', '.', '?' }, StringSplitOptions.RemoveEmptyEntries).Length; } } // 操作界面类 class Program { static void Main(string[] args) { Operation operation; operation = OperationFactory.CreateOperate("+"); operation.NumberA = 1; operation.NumberB = 2; double result = operation.GetResult(); // 调用扩大办法 string s = "Hello Extension Methods"; s.Count(); } }}封装:创立计算基类、工厂类和界面类让业务逻辑与界面逻辑离开,让它们之间的耦合度降落。 ...

December 23, 2020 · 2 min · jiezi

关于c#:如何在-ASPNET-Core-中处理-404-错误

译文链接:https://www.infoworld.com/art...asp.net core mvc 对应着 .NET Framework 中的 ASP.NET MVC, 前者能够跨平台,可扩大,高性能,不过令人诧异的是,尽管 ASP.NET Core 提供了大量的可选项能够完满的解决 404 谬误,但 ASP.NET Core MVC 在默认状况下并没有抉择它们,你说奇怪不? 这就造成了当申请一个不存在的页面时,应用程序将会返回一个 404 谬误,ASP.NET Core MVC 目前会展现一个浏览器通用的谬误页,如下图所示: 这篇文章我筹备探讨 3种 形式来优雅的解决这种 404 谬误。 接下来我会在 Visual Studio 2019 中创立一个 ASP.NET Core MVC 我的项目,用这个我的项目去展现如何解决 404 谬误。 而后把 ASP.NET Core MVC 我的项目跑起来,你会看到应用程序默认的首页,下面还带一行 welcome 的欢送语????,如下图所示: 接下来咱们尝试在浏览器中输出一个不存在的网址,比如说:http://localhost:6440/welcome, 这时候 ASP.NET Core MVC 引擎将会拜访这个地址的资源,可想而知,引擎必定会返回一个 404 谬误,你也会看到如下谬误页,通常状况下这是十分让人难堪的,对吧。 查看 ASP.NET Core MVC 的 Response.StatusCode有几种形式能够比拟完满的解决这种默认的 404 谬误,一个简略的计划就是去查看 response 的 http 状态码,一旦发现这个 status = 404,你能够重定向到一个web 中存在的页面或者一个特定的谬误页,上面的代码展现了,你能够在 Startup.Configure 办法中进行全局判断,一旦发现404谬误就导向 home 页面。 ...

December 23, 2020 · 2 min · jiezi

关于c#:如何在-C-中使用-Attribute

译文链接:https://www.infoworld.com/art...Attribute 在 C# 中是一个十分弱小的个性,它可能给你的程序集增加元数据信息。 Attribute 实际上是一个对象,它能够与以下元素中的任何一个相关联: 程序集、类、办法、委托、枚举、事件、字段、接口、属性和构造,它会在这些对象上做信息申明,当程序运行之后,你能够通过反射来获取关联到这些对象上的 Attribute 信息,换句话说:你能够通过 Atrribute 向程序集注入一些额定信息,而后在运行时通过反射来获取,attribute 个别由 名字 + 一些可选参数 形成, attribute 名字对应着 atrribute 类。 你能够利用 attribute 去校验你的业务model的正确性, attribute 有两种:内置 + 自定义, 前者是 .net framework 框架的组成部分,后者须要通过继承 System.Attribute 类来实现自定义。 当初来看看代码怎么写,Obsolete 个性用来标记一个办法是过期的,这个过期的意思是:你不应该再应用这个办法了,将来框架也会将其剔除,目前也存在其代替计划。其实在第三方框架中有很多这样的例子,上面的代码片段展现了如何在办法顶部应用 Obsolete 个性。 [Obsolete("This method is obsolete...")]public static void DoSomeWork(){}如果你在程序中调用了这个办法,当你编译代码时,在 Visual Studio 输入窗口中会当初一些正告信息,如下图: 当然,如果你肯定要漠视它也是能够的,当初,如果你心愿你的开发共事不容许调用这个办法,那如何去限定呢?哈哈,能够应用 Obsolete 的第二个参数,这个参数是可选的,上面是 DoSomeWork() 办法的批改版本,请留神这是一个 Boolean 型参数。 [Obsolete("This method is obsolete...", true)] public static void DoSomeWork() { }当把 true 给了这个可选参数后,再次编译代码,你会发现代码基本编译不通过,是不是完满的解决了你的问题,是吧! 截图如下: ...

December 23, 2020 · 2 min · jiezi

关于c#:如何使用-C-中的-Action-FuncPredicate

译文链接:https://www.infoworld.com/art...委托是一个类型平安的函数指针,它能够援用与委托具备雷同签名的办法。委托罕用于实现回调办法或者事件机制,在C#中个别用 "delegate" 关键字申明。你能够申明一个和类平级的委托,也能够嵌套在类中。 Func 和 Action 是什么,如何应用?两者最根本的区别是,前者适宜那些须要带返回值的委托,后者适宜那些不带返回值的委托。 Func 所援用的办法接管一个或者多个入参并带有一个返回值,Action所援用的办法接管一个或者多个参数并且没有返回值,换句话说,你的委托所援用的办法没有返回值,这时候适宜用 Action。 Predicate所援用的办法接管一个或者多个泛型参数并且返回一个 bool 值,你能够假设它等价于 Func<T,bool>,Predicate 罕用于对 collection 进行一组条件检索。 C# 中应用 Action你能够应用 委托 去实现事件和回调办法,C#委托十分相似于C++中的函数指针,然而 C# 中的 委托 是类型平安的,你能够将办法作为参数传递给委托从而让委托指向该办法。 上面的代码片段展现了 Action 委托的语法结构。 Action<TParameter>接下来的代码清单展现了如何应用 Action 委托,当上面的代码执行完结后会在控制台打印 Hello !!!。 static void Main(string[] args) { Action<string> action = new Action<string>(Display); action("Hello!!!"); Console.Read(); } static void Display(string message) { Console.WriteLine(message); }C# 中应用 Func当初咱们一起学习下 Func 委托,上面是 Func 的语法结构。 Func<TParameter, TOutput>接下来的代码片段展现了如何在 C# 中应用 Func 委托,最终办法会打印出 Hra(根本薪资的 40%) 的值,根本薪资是作为参数传下去的,如下代码所示: ...

December 23, 2020 · 2 min · jiezi

关于c#:C中的深度学习三理解神经网络结构

在这篇文章中,咱们将回顾监督机器学习的基础知识,以及训练和验证阶段包含哪些内容。 在这里,咱们将为不理解AI的读者介绍机器学习(ML)的基础知识,并且咱们将形容在监督机器学习模型中的训练和验证步骤。 ML是AI的一个分支,它试图通过演绎一组示例而不是接管显式指令来让机器找出如何执行工作。ML有三种范式:监督学习、非监督学习和强化学习。在监督学习中,一个模型(咱们将在上面探讨)通过一个称为训练的过程进行学习,在这个过程中,它会提供示例输出和正确输入。它理解数据集示例中哪些个性映射到特定输入,而后可能在一个称为预测的阶段预测新的输出数据。在无监督学习中,模型通过剖析数据之间的关系来学习数据的构造,而不波及任何其余过程。在强化学习中,咱们建设模型,通过试验和谬误技术,随着工夫的推移学习和改良。 ML中的模型是什么?模型是一个简略的数学对象或实体,它蕴含一些对于AI的实践背景,以便可能从数据集学习。在监督学习中风行的模型包含决策树、向量机,当然还有神经网络。 神经网络是按堆栈的形态分层排列的。除了输出层和输入层之外,每一层的节点都接管来自上一层节点的输出,也能够接管来自下一层节点的输出,同样也能够向上一层和下一层节点发送信号或输入。在一个神经网络中,咱们总是存在输出和输入层,可能有一个或多个暗藏层。 最简略的NN是感知器,它是蕴含的输出层和输入层单个节点。 对于神经网络中的每条边都有一个关联的权重值,这是对于每个节点都有关联的值。例如,输出层中每个节点的值能够来自与数据集中的图像相关联的像素值输出数组。为了计算下一层节点的值,咱们计算连贯到该节点的输出的加权和。这就是传递函数。一旦计算出这个值,它就被传递给另一个称为激活函数的函数,该函数依据阈值确定该节点是否应该触发到下一层。有些激活函数是二进制的,有些则有多个输入。通常在神经网络的开端,咱们有一个激活函数,它对传递到输出层的数据进行分类(做出决定)。在硬币辨认的状况下,它将决定图像中硬币的类别或类型。神经网络中的学习过程能够仅仅看作是对其权重的调整,以便为每个给定的输出取得预期的输入。一旦对模型进行了训练,失去的权重就能够被保留下来。 当一个神经网络有一个以上的暗藏层时,咱们将其称为深度学习(DL)。DL是一套依赖于神经网络且不止一个暗藏层的技术。领有多个暗藏层的起因是提供比繁多暗藏层神经网络更精确的后果。实践证明,深度神经网络比单层神经网络能产生更快更精确的后果。你增加到你的神经网络的每一层都有助于从数据集学习简单的特色。 神经网络蕴含许多须要调整以取得更好性能的参数。为了可能查看参数优化的有效性和神经网络自身的性能,咱们留出很大一部分的原始数据集(通常大于70%)作为训练集,应用其余验证(测试)组。验证集也帮忙咱们避免适度拟合,这产生在一个模型学习太好一组十分类似的对象数据集,使它太适宜这个数据和不适宜新数据。 在下一篇文章中,咱们将钻研用于硬币辨认问题的卷积神经网络,并将在Keras.NET中实现一个卷积神经网络。 欢送关注我的公众号,如果你有喜爱的外文技术文章,能够通过公众号留言举荐给我。

December 23, 2020 · 1 min · jiezi

关于c#:如何在-NET-中使用-Redis缓存

译文链接:https://www.infoworld.com/art...缓存是一种状态管理机制,通常用于晋升你的应用程序性能,它很大水平上可能缩小一个申请对你系统资源的耗费。 Redis是一个开源的,高性能的,NoSql数据库,它的速度十分快,而且所有的数据都是灌入到内存中,从内存中读写数据的性能开销真的是微不足道,值得一提的是 Redis 采纳的是BSD license,阐明你能够将它用于商业和非商业的用处。 Redis是什么,我为什么要用它?Redis 是最风行的开源,NoSQL,基于内存的数据存储,而且十分????的是:它的数据存储反对多个数据结构,eg:strings,hashes,sets,lists 等等,Redis外部也提供了对 复制散发 和 事务 的反对,同时在数据长久化方面也做的十分好。 如果你的应用程序须要读取大量的数据,并且你的机器有很多的闲暇内存,在这样的场景下如果你有晋升性能的需要,采纳 Redis 是一个十分好的抉择,将Redis利用到你的程序中操作步骤也是非常简单的,接下来咱们会一起探讨下如何去装置,配置和应用。 装置Redis本篇探讨下如何在 Windows 平台上装置 Redis,安装包能够到 GitHub: https://github.com/MSOpenTech... 去下载,在装置的过程中,记得勾选一下 add Redis to the PATH environmental variable,将 Redis的门路增加到环境变量中,等到安装程序执行结束之后,能够通过 Run -> service.msc 到 windows 的服务面板去看下 redis service 是否曾经装置胜利。 应用 Redis Client Sdk当初 redis 曾经胜利装置到你的零碎中了,接下来你须要一个 client sdk 去连贯 redis server 来读取数据,在上面的例子中,我会应用开源的 ServiceStack 这个sdk,接下来在 Visual Studio 中创立一个 Console 应用程序,而后通过 NuGet packkage manager 来装置 ServiceStack.Redis。 假设当初 ServiceStack.Redis 曾经通过 NuGet 胜利装置,上面的两个办法展现了连贯 Redis server 来发送和读取数据。 ...

December 22, 2020 · 1 min · jiezi

关于c#:如何在-C-中使用-Dapper-ORM

译文链接:https://www.infoworld.com/art...对象关系映射(ORM)这个概念曾经存在很长时间了,ORM的作用就是用来解决 编程畛域的 object model 和关系数据库中的 data model 的不匹配问题,Dapper 是一个开源的,轻量级的 ORM 框架,由 Stack Overflow 团队开发,Dapper 和其余风行的ORM框架相比,最大的长处就是羽翼级。 Dapper在最后开发时就思考到了性能和易用性,它反对在 事务,存储过程 或者 批量插入时进行动态或者动静的对象绑定。 应用 Visual Studio 装置 Dapper ORM要想理解 Dapper,从上面的步骤开始吧: 关上 Visual Studio点击 文件 -> 新建 -> 我的项目抉择 网站 -> ASP.Net Web Application给 web 我的项目指定一个名字而后抉择一个 空模板点击 确定 生成 project这样咱们就创立好了一个 ASP.Net web application 我的项目 如果你曾经装置了 NuGet,你能够通过 NuGet 去装置 Dapper,做法就是在 解决方案窗口 下的 Project 上右键抉择 Manage NuGet Package ... 并且找到 Dapper,而后点击装置开启这个装置过程,一旦 Dapper 被胜利装置,你就能够欢快的玩起来了哈。 ...

December 22, 2020 · 2 min · jiezi

关于c#:如何在-AspNet-Core-MVC-中处理-null-值

译文链接:https://www.infoworld.com/art...传统的 asp.net mvc 对应着 .netcore 中的 asp.net core mvc,能够利用 asp.net core mvc 去构建跨平台,可扩大,高性能的web利用和 api 接口。 程序员都有一些洁癖,很多时候咱们都想很完满的包装一些错误信息,如一些返回空response的request申请,或者一些 action 中返回 null value 的状况,通常这些状况下,asp.net core mvc 都会返回 http status 204 (No Content),在本篇中,我筹备批改一下这种从 action 返回 null value 的默认行为。 要想运行本篇的例子,你须要装置一下 Visual Studio 2019,如果没有装置,能够到官网装置一下: https://visualstudio.microsof... 在 Asp.NET Core 中新建 Controller在解决方案窗口中的 Controller 文件夹上右键并抉择 Add -> Controller 去新建Controller,指定这个 Controller 的名字为 DemoController,接下来用上面的代码替换 DemoController。 [Route("api/[controller]")] [ApiController] public class DemoController : ControllerBase { readonly Repository repository = new Repository(); [HttpGet] public ActionResult Get() { string item = repository.GetMessage(); return Ok(item); } [HttpGet("{id}", Name = "Get")] public IActionResult Get(int id) { string item = repository.GetMessage(); return Ok(item); } }创立一个 Repository上面是一个 Repository 类,外面蕴含了一个返回 null 的 GetMessage 办法,当然这仅仅是为了演示目标。 ...

December 22, 2020 · 2 min · jiezi

关于c#:如何在-C-中使用-RabbitMQ

译文链接:https://www.infoworld.com/art...RabbitMQ 是一个十分风行的,开源的,应用Erlang语言编写的框架,通常在电信级平台中作为消息中间件应用,RabbitMQ实现了高级的AMQP协定用于实现过程间,应用程序间,服务器之间的音讯交互,而且它还有一个十分????????的个性,你能够应用自定义插件来扩大RabbitMQ的性能,而且它还反对多协定,高性能,高牢靠,集群以及高可用队列。 创立队列的形式也多种多样,你能够编码创立,也能够通过管理员用户界面,甚至通过 PowerShell 进行队列创立。 RabbitMQ 术语当你在用 RabbitMQ 时,你要了解上面两个术语 队列是一个数据结构上的概念,反对 FIFO 个性,在本文中,音讯队列就是一个能够寄存音讯的微小缓存。producer(生产者) 的使命是生成数据并推送到队列的一种角色组件,consumer(消费者)它可能从存储音讯的队列中提取数据进行生产,生产者-消费者 是并行编程中十分风行的设计模式之一。装置和启动装置 RabbitMQ 是非常简单的,在装置之前,你须要先装置 Erlang,依据你的操作系统抉择正确版本呢的 Erlang,下载地址:https://www.erlang.org/downloads ,而后持续下载安装 RabbitMQ Server ,下载地址: https://www.rabbitmq.com/down... 用 C# 构建 RabbitMQ当初 Erlang 和 RabbitMQ 曾经胜利装置到你的windows上,如果想和 Rabbitmq Server 进行交互,你须要装置一个 RabbitMQ .NET client , 能够用 NuGet Package Manager 控制台去装置 RabbitMQ Client。 在 Visual Studio 中新建一个 Console Application,而后通过 NuGet Package Manager 装置 RabbitMQ.Client 开发包,假设 RabbitMQ Server 是运行在本机,上面的代码片段创立了一个和 RabbitMQ Server 交互的 Connection 连贯,代码如下: ConnectionFactory connectionFactory = new ConnectionFactory();IConnection connection = connectionFactory.CreateConnection();当初再次假设 RabbitMQ 跑在近程服务器上,上面的办法返回了一个通往 Rabbitmq Service 的 Connection 连贯。 ...

December 22, 2020 · 2 min · jiezi

关于c#:命名空间

命名空间与类型有些类似,在类型中能够申明诸多成员:字段,属性,办法,而在命名空间中能够申明:类,接口 命名空间属于逻辑组合,用来对类型的性能进行逻辑分组成员依据相关性能够将name, age, sex成员定义到Person类型中类型能够把Dog, Cat类型定义到名为Animal的命名空间里 申明命名空间的构造namespace 名字 { }命名空间不能有修饰符如拜访修饰符//谬误,不能应用修饰符private namespace 名字 { }申明Animal命名空间namespace Animal { }*命名空间的命名规定可参考变量名(可查看往期文章变量和常量) 命名空间中不能蕴含成员: 字段,属性,办法namespace Animal{ private int id; //谬误 public int Id { get; set; } //谬误 private void Test() { } //谬误}类型名必须惟一,同一个命名空间中无奈定义同样的类型namespace Animal{ //正确 class Dog { } //谬误,命名空间 Animal中曾经蕴含了Dog的定义 class Dog { }}*如果未给类型显示提供命名空间,该类型将会被编译器默认放到一个没有名称的全局命名空间(global namespace)中 //正确class Dog { }//谬误,命名空间 global namespace中曾经蕴含了Dog的定义class Dog { }*就像类型中无奈定义多个雷同名称的成员一样,类型名也须要具备唯一性 命名空间的另一个作用便是进步类型名的唯一性,无奈在同一个名称空间下定义雷同的类型,实质起因也是类型名需惟一 所以能够写出上面这样的代码 //正确class Dog { }namespace Animal{ //正确,属于不同命名空间 class Dog { }}起因: 两个Dog类型分属不同的名称空间,属于全局命名空间的Dog类型名:Dog,属于Animal命名空间的Dog类型名: Animal.Dog 拜访不同命名空间中的类型(全局命名空间类型除外)须要应用类型限定名,同一个命名空间下则不须要 namespace Animal{ class Dog { void Test() { //正确 Dog dog = new Dog(); } }}namespace A{ class Person { void Test() { //谬误,未找到类型名 Dog dog = new Dog(); //正确 Animal.Dog dog = new Animal.Dog(); } }}然而这样的代码过于繁琐,同时也升高了代码的可读性 ...

December 21, 2020 · 2 min · jiezi

关于c#:如何使用-C-中的-HashSet

译文链接:https://www.infoworld.com/art...HashSet 是一个优化过的无序汇合,提供对元素的高速查找和高性能的set汇合操作,而且 HashSet 是在 .NET 3.5 中被引入的,在 System.Collection.Generic 命名空间下,这篇就来讨论一下如何应用这个 HashSet。 要运行本篇文章的案例代码,你须要装置一下 Visual Studio 2019,如果没有的话能够到官网下载一下。 应用 VS 创立一个 .NET Core 控制台程序首先,我通过 VS2019 创立一个 .NET Core 控制台程序,创立能够参考上面步骤: 关上 Visual Studio IDE点击创立 Create new project在 Create new project 窗口上,从模板列表中抉择:Console App (.NET Core)点击下一步在 Configure your new project 界面填好你的项目名称和寄存门路这样咱们就创立好了一个新我的项目,本文的前面局部就会在这个我的项目里来给大家分享 HashSet 的一些必备常识。 HashSet 到底是什么所谓的HashSet,指的就是 System.Collections.Generic 命名空间下的 HashSet<T> 类,它是一个高性能,无序的汇合,因而HashSet它并不能做排序操作,也不能蕴含任何反复的元素,Hashset 也不能像数组那样应用索引,所以在 HashSet 上你无奈应用 for 循环,只能应用 foreach 进行迭代,HashSet 通常用在解决元素的唯一性上有着超高的性能。 HashSet<T> 实现了如下几个接口: public class HashSet<T> : System.Collections.Generic.ICollection<T>,System.Collections.Generic.IEnumerable<T>, System.Collections.Generic.IReadOnlyCollection<T>,System.Collections.Generic.ISet<T>,System.Runtime.Serialization.IDeserializationCallback,System.Runtime.Serialization.ISerializable{}HashSet 只能蕴含惟一的元素,它的内部结构也为此做了专门的优化,值得注意的是,HashSet 也能够寄存单个的 null 值,能够得出这么一个论断:如何你想领有一个具备惟一值的汇合,那么 HashSet 就是你最好的抉择,何况它还具备超高的检索性能。 ...

December 21, 2020 · 2 min · jiezi

关于c#:如何使用-C-扩展方法

译文链接:https://www.infoworld.com/art... C# 在 3.0 版本中提供了对 扩大办法 的反对,扩大办法罕用于给一个已存在的类增加新的办法从而扩大该类的性能,最要害的是:你不须要在现存类中派生一个子类,你也不须要破坏性的批改类的现有代码骨架,更谈不上从新编译了,扩大办法可能提供代码的可读性同时又能够扩大类的性能。 .NET 框架中最常见的扩大办法包含 Linq 规范的查问操作,这类扩大办法极大的扩大了System.Collections.IEnumerable 和 System.Collections.Generic.IEnumerable<T> 的查问能力,如下图: 当初你明确了扩大办法,你能够用这项技术去给已存在的 class 或者 interface 增加更多实用办法而不应该从子类中新增额定的办法,MSDN上说:扩大办法容许你给现有的类 增加 办法,而不须要你生成子类,从新编译,或者任何其余模式的批改原有类,扩大办法是一种非凡的静态方法,当你调用它的时候就如同它就是你扩大类的原生办法。 实质上来说,扩大办法也算是一种非凡的静态方法,它容许你给已存在的类增加新的办法即便你没有权限拜访这个扩大类的源代码,扩大办法除了签名中的第一个参数是 this 之外就和静态方法是截然不同,你能够给任何一个类增加任意多的扩大办法,更????????的是:这个扩大办法个性还能够作用到值类型之上。 当你应用扩大办法的时候,请记住上面的几个点: 扩大办法必须是一个静态方法扩大办法必须在 static class 内,类的名字无所谓扩大办法的第一个参数肯定是 this,前面跟上你须要扩大的类型有一点要特地留神,如果扩大办法的名字和你要扩大类中的某一个办法重名了,那么你的扩大办法将会生效,永远也不会被调用。 应用 C# 扩大办法这一节中咱们一起探讨下如何应用 C# 来实现一个扩大办法,上面的代码清单展现了 C# 中的扩大办法到底长成什么样? public static class StringExtensions { public static bool IsNumeric(this string str) { double output; return double.TryParse(str, out output); } }请留神扩大办法中的第一个参数,正如之前探讨过的,任何扩大办法都必须是动态的,而且在参数之前还要申明一下 this 关键词,比方像下面这个例子一样,相当于通知了编译器你曾经在 string 类上扩大了一个 IsNumeric 办法。 接下来一起看一下如何在 string 类中应用 IsNumeric 办法。 ...

December 21, 2020 · 1 min · jiezi

关于c#:如何在-C-中使用-AutoMapper

译文链接: https://www.infoworld.com/art...AutoMapper 是一个十分风行的 object-to-object 映射库,它的目标就是帮忙你实现不同类型对象之间的映射,举一个例子,在 DDD 开发模式中,你可能须要实现将 DTO object 映射为 Model object,在过来,你须要人肉的将这两个类型下的属性字段进行一一映射,当初 AutoMapper 就能够帮你节俭 这种冗余的模板式代码 匹配所消耗的工夫。 开始玩 AutoMapper 之前,你须要在 Visual Studio 中创立一个 Project 并且装置 AutoMapper,你能够从 NuGet 上下载,也能够在 NuGet Package Manager Console 控制台输出如下命令: PM> Install-Package AutoMapper应用 AutoMapper 创立映射关系像 AutoMapper 这样的 object-to-object 映射工具,它必须可能做到将一种输出类型转换成另一个输入类型,是不是很拗口,能够先思考上面的两个类。 public class AuthorModel { public int Id { get; set; } public string FirstName { get;set; } public string LastName { get; set; } public string Address { get; set; } } public class AuthorDTO { public int Id { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public string Address { get; set; } }接下来,上面的代码段将会告知你如何应用 AutoMapper 在 AuthorModel 和 AuthorDTO 这两个对象之间创立一个 mapping 关系。 ...

December 21, 2020 · 3 min · jiezi

关于c#:用-C-实现一个简单的日志框架

译文链接: https://www.infoworld.com/art...在你的 .NET 程序中常常会记录一些日志或者谬误,为了实现这个性能,你可能会应用市面上那些现成的日志框架(log4net,nlog ...),当然你也能够设计并开发一个本人的日志框架,在这篇文章中,我将会带你一起如何轻松愉快的创立一个自定义日志框架,并且一步一步的构建这个简略的 logger。 首先,你要晓得什么叫 log targets,从字面意思看就是你的日志要输送到哪里?能够假设咱们的日志能够输入到: 文件,数据库 或者 windows 日志 中,上面我在 日志框架 中定义一个枚举示意这三个输出地。 public enum LogTarget { File, Database, EventLog }构建 logger 类接下来实现一下 logger 类,我筹备定义三个类来示意这三个output,FileLogger, DBLogger, EventLog ,所有的这些类都须要继承基类 LogBase,上面上一下代码展现一下这些类的继承关系。 public abstract class LogBase { public abstract void Log(string message); } public class FileLogger : LogBase { public string filePath = @”D:\IDGLog.txt”; public override void Log(string message) { using (StreamWriter streamWriter = new StreamWriter(filePath)) { streamWriter.WriteLine(message); streamWriter.Close(); } } } public class DBLogger : LogBase { string connectionString = string.Empty; public override void Log(string message) { //Code to log data to the database } } public class EventLogger: LogBase { public override void Log(string message) { EventLog eventLog = new EventLog(“”); eventLog.Source ="IDGEventLog"; eventLog.WriteEntry(message); } } 下面 DBLogger 的 Log 办法我成心没有实现,你能够在学习完本文后本人来实现这一块的逻辑,将日志记录到数据库中。 ...

December 21, 2020 · 2 min · jiezi

关于c#:如何使用-C-构建自己的-task-scheduler

译文链接: https://www.infoworld.com/art...TPL(工作并行库)是 .NET Framework 最新版本中最乏味的新性能之一,在.NET Framework 4.0 中被引入。要应用TPL,您须要援用 System.Threading.Tasks 命名空间。 什么是 task schedulers?为什么须要它们?如果我想问,Task 是如何被调度执行的?其实有一个组件叫做 task scheduler,它专门负责调度 task。从实质上来说,这是一个底层对象的形象层,它能够将您的 task 通过排队调度到线程上。 .NET Framework 为您提供了两个 task schedulers。包含基于默认的 task scheduler 用于调度在 Thread Pool 之上,另一个 task scheduler 可能调度在 指定对象的同步上下文上。请留神,TPL的默认 task scheduler 利用了.NET Framework 线程池。该线程池的示意类 ThreadPool 是在 System.Threading.Tasks命名空间下。 只管默认的 task scheduler 在大多数状况下已足够,但有时候你兴许也想构建自定义的 task scheduler 去实现个性化的性能,比方那些默认的 task scheduler 没有提供的。此类性能可能包含 FIFO执行,并发度等。 在C#中扩大 TaskScheduler要构建自定义的 task scheduler,您须要创立一个类并继承 System.Threading.Tasks.TaskScheduler 。因而,要构建自定义的 task scheduler,您须要扩大 TaskScheduler抽象类并重写以下办法。 QueueTask 返回void并承受Task对象作为参数,当一个 task 须要调度的时候就要调用这个办法GetScheduledTasks 返回所有已被调用的 task list, (精确的说是IEnumerable)TryExecuteTaskInline 用于内联形式(即在以后线程上)执行task。在这种状况下,无需排队即可执行 task上面的代码段展现了如何继承 TaskScheduler 类来实现咱们自定义的 scheduler。 ...

December 21, 2020 · 2 min · jiezi

关于c#:反射特性和动态编程

反射反射是指对程序集中的元数据(如:办法、类型、参数、字段、属性、自定义个性等)进行查看的过程。咱们是通过System.Type的实例来拜访类型的元数据。 应用System.Type拜访元数据读取类型的元数据,首先要取得System.Type的一个实例,它代表了指标类型实例。System.Type提供了获取类型信息的所有办法。次要是通过object.GetType()和typeof()操作符达到这个目标。 应用GetType()Object 对象蕴含一个GetType()成员,胜利调用GetType()的关键在于取得一个对象实例。例如:动态类无奈实例化,无奈调用GetType()。DateTime dateTime = new DateTime();Type type = dateTime.GetType();// 获取该类型的所有公共属性foreach (System.Reflection.PropertyInfo property in type.GetProperties()){ Console.WriteLine(property.Name);}输入: typeof()在编译时绑定到特定的Type实例,并间接获取类型作为参数。 int value = (int)Enum.Parse(typeof(ThreadPriorityLevel), "Idle"); Console.WriteLine(value);也能够应用typeof表达式验证value对象的类型: if (value.GetType() == typeof(int)) { // ... } 其中GetType() 在运行时返回对象的类型(早期绑定),typeof()返回指定类的类型(晚期绑定,编译时已知)尽量采纳typeof()这个操作符获取Type对象,因为操作符生成的代码通常更快。 成员调用应用System.Type拜访元数据后,可调用他们。 public class MagicClass{ private int magicBaseValue; public MagicClass() { magicBaseValue = 9; } public int ItsMagic(int preMagic) { return preMagic * magicBaseValue; }}class Program{ static void Main(string[] args) { // 获取构造函数,并创立一个MagicClass的实例 Type magicType = typeof(MagicClass); ConstructorInfo magicConstructor = magicType.GetConstructor(Type.EmptyTypes); object magicClassObject = magicConstructor.Invoke( new object[] { }); // 获取ItsMagic办法并应用100的参数值进行调用 MethodInfo magicMethod = magicType.GetMethod("ItsMagic"); // Invoke办法第一个值为:要在其上调用办法或构造函数的实例对象 // Invoke办法第一个值为:被调用办法或构造函数的参数列表。 object magicValue = magicMethod.Invoke(magicClassObject, new object[] { 100 }); Console.WriteLine("MethodInfo.Invoke()"); Console.WriteLine("MagicClass.ItsMagic() returned: {0}", magicValue); }后果: ...

December 20, 2020 · 1 min · jiezi

关于c#:可空值类型

可空值类型援用类型的变量能够为空,值类型的变量则不被容许赋值为null,而可空值类型便是能够赋值为null的值类型。 可空值类型的申明与初始化int? x = null;int? y = 1;类型之间的转换int转int?总是会胜利int? a = 5; //正确int?转int须要显示转换int c = a; //谬误,无奈从int?隐式转换为intint c = (int)a; //正确可空基元类型之间的转型int? b = null;//d=5double? d = 5;//e=nulldouble? e = b;C#对可空值类型利用操作符规定一元操作符(++,+,-,--,!,~):操作数是null,后果就是nullint? a = null;Console.WriteLine(a++); //nullConsole.WriteLine(a + 10); //null二元操作符(+,-,*,/,%,&,|,^,<<,>>):两个操作数其中一个为null,后果就为null。特例:&,|和Boolean?类型的操作数时,状况如下bool? a = null;bool? b = true;Console.WriteLine(a & b); //后果为nullConsole.WriteLine(a | b); //后果为truebool? c = false;Console.WriteLine(a & c); //后果为falseConsole.WriteLine(a | c); //后果为null相等性操作符(==,!=):两个操作数皆为null,两者相等;一个为null,一个不为null,则不等;皆不为null,则比拟数值是否相等。int? a = null;int? b = null;int? c = 10;Console.WriteLine(a == b); //trueConsole.WriteLine(a == c); //false关系操作符(<,>,<=,>=):两个操作数任意一个为null,返回false。两个操作数都不是null,就比拟值返回后果。int? a = null;int? b = null;int? c = 10;Console.WriteLine(a > b); //falseConsole.WriteLine(a > c); //false空接合操作符(??)??:获取两个操作数,如果右边的操作数不为null,则返回右边操作数的值,反之返回左边操作数的值。 ...

December 16, 2020 · 2 min · jiezi

关于c#:C实现代码生成器客户端

做了2,3年的java-web,始终木有逃离所谓根底业务,增删改查这些变化无穷的货色写起来节约大量工夫,于是做了个简略的代码生成器疾速生成 代码生成器的原理其实很简略,都是基于模板实现替换,模板基于是Nvelocity。 局部代码展现:【目前只反对mysql 、oracle、sqlite 三种数据库的连贯 有须要 能够本人减少】 sing System;using System.Collections.Generic;using System.Data;using System.Linq;using System.Text;using System.Threading.Tasks;using personal_manage.Common.DAL;using personal_manage.Common.dto;using personal_manage.DAL.adapter;using personal_manage.Models.entity;namespace personal_manage.BLL.adapter{ public class DbBLL { public List<TableInfo> SelectTableList(CodeProjectDbConfigInfo codeProjectDbConfigInfo, string tableKeyword) { if (codeProjectDbConfigInfo.DbType == "Mysql" ) { return DbAdapter.SelectTableNameByMySql(codeProjectDbConfigInfo.DbConnect, codeProjectDbConfigInfo.DbName, tableKeyword); }else if(codeProjectDbConfigInfo.DbType == "Oracle") { return DbAdapter.SelectTableNameByOracle(codeProjectDbConfigInfo.DbConnect, codeProjectDbConfigInfo.DbName, tableKeyword); } else if (codeProjectDbConfigInfo.DbType == "Sqlite") { return DbAdapter.SelectTableNameBySqlite(codeProjectDbConfigInfo.DbConnect, codeProjectDbConfigInfo.DbName, tableKeyword); } return null; } public List<TableFieldInfo> SelectTableFields(CodeProjectDbConfigInfo codeProjectDbConfigInfo, string tableName) { if (codeProjectDbConfigInfo.DbType == "Mysql") { return DbAdapter.SelectTableFieldsByMySql(codeProjectDbConfigInfo.DbConnect, codeProjectDbConfigInfo.DbName, tableName); } else if (codeProjectDbConfigInfo.DbType == "Oracle") { return DbAdapter.SelectTableFieldsByOracle(codeProjectDbConfigInfo.DbConnect, codeProjectDbConfigInfo.DbName, tableName); } else if (codeProjectDbConfigInfo.DbType == "Sqlite") { return DbAdapter.SelectTableFieldsBySqlite(codeProjectDbConfigInfo.DbConnect, codeProjectDbConfigInfo.DbName, tableName); } return null; } }}演示界面:数据库配置 ...

December 13, 2020 · 1 min · jiezi

关于c#:Attribute

attribute可利用于类型和成员是类的一个实例从System.Attribute派生C# attribute应用范畴程序集模块类型(类、构造、枚举、接口、委托)字段办法(含结构器)办法参数办法返回值属性事件泛型类型参数FCL定义的Attribute列举Serializable:利用于类型,通知序列化格式化器,一个实例的字段能够呗序列化和反序列化Flags:利用于枚举类型,将枚举类型作为一个位标记(bit flag)汇合应用默认自定义的attribute类能用于任何指标元素public class MyAttribute : Attribute{ public MyAttribute() { }}[MyAttribute]class Program{ [MyAttribute] static void Main(string[] args) { }}限定attribute的应用范畴:枚举类型 [AttributeUsage(AttributeTargets.Enum, AllowMultiple = false, Inherited = false)]public class MyEnumAttribute : Attribute{ public MyEnumAttribute() { }}以上代码利用AttributeUsage告知编译器定制attribute的非法利用范畴,如果将定制attribute利用于一个有效指标时将会报错 [MyEnumAttribute] //正确public enum MyEnum { }[MyEnumAttribute] //谬误:只对枚举无效class Program{}AllowMultiple和InheritedAllowMultiple:不显示设置为true就只能向一个选定指标利用一次Inherited:指明在attribute利用于基类的时候是否同时利用于派生类和重写办法上[AttributeUsage(AttributeTargets.Enum, AllowMultiple = false, Inherited = false)]public class MyEnumAttribute : Attribute{ public MyEnumAttribute() { }}//谬误:个性反复[MyEnumAttribute][MyEnumAttribute]public enum MyEnum { }/*------------------------------*/[AttributeUsage(AttributeTargets.Enum, AllowMultiple = true, Inherited = false)]public class MyEnumAttribute : Attribute{ public MyEnumAttribute() { }}//正确[MyEnumAttribute][MyEnumAttribute]public enum MyEnum { }定制attribute时能够应用结构器获取参数,在应用过程中,必须传递一个编译时常量表达式。传递参数规定: ...

December 9, 2020 · 2 min · jiezi

关于c#:对-精致码农大佬-说的-TaskRun-会存在-内存泄漏-的思考

一:背景1. 讲故事这段时间我的项目延期,加班比拟厉害,博客就略微停了停,不过还是得继续的技术输入呀! 园子里最近挺冷落的,粗劣码农大佬分享了三篇文章: 为什么要小心应用 Task.Run [https://www.cnblogs.com/willi...]小心应用 Task.Run 续篇 [https://www.cnblogs.com/willi...]小心应用 Task.Run 终篇解惑 [https://mp.weixin.qq.com/s/IM...]外围代码如下: class Program { static void Main(string[] args) { Test(); Console.ReadLine(); } static void Test() { var myClass = new MyClass(); myClass.Foo(); } } public class MyClass { private int _id = 10; public Task Foo() { return Task.Run(() => { Console.WriteLine($"Task.Run is executing with ID {_id}"); }); } }粗心是: Test() 办法执行完之后, myClass 本该销毁,后果发现 Foo() 办法援用了 _id ,导致 GC 放弃了对 myClass 的回收,从而导致内存透露。如果我的了解有误,请大家帮忙斧正,挺有意思,评论区也是热闹非凡,总体看下来发现还是有很多敌人对 闭包, 内存透露,GC 等概念的认知比拟含糊,同样作为技术博主,得要蹭点热度????????????,这篇我筹备从这三个方面论述下我的认知,而后大家再回头看一下 粗劣 大佬的文章。 ...

December 9, 2020 · 3 min · jiezi

关于c#:委托

委托在C++中,函数指针是一个指向内存地位的指针,它不是类型平安的,咱们无奈判断这个指针理论指向什么,包含参数和返回类型也无从通晓。而.NET委托齐全不同,委托类型是平安的,是用户自定义的存储了一系列具备雷同签名和返回类型的办法的地址的自定义类型。不仅蕴含对办法的援用,也能够蕴含对多个办法的援用。 申明委托delegate void m_CustomDelegate(string msg);这段代码应用delegate关键字申明了一个委托类型,它的实例将会援用一个返回类型为void并且承受一个string类型参数的办法。 委托的应用var testDel = new CustomDelegate(StaticDelegate);//将会在控制台打印输出:msg : 回调静态方法testDel("回调静态方法");testDel.Invoke("回调静态方法");static void StaticDelegate(string msg){ Console.WriteLine("msg : {0}", msg);}协变性和逆变性协变性:办法能够返回从委托的返回类型派生的一个类型逆变性:办法获取的参数能够是委托的参数类型的基类示例代码: delegate object CallBack(FileStream stream);//正确var callback = new CallBack(CallMethod);static string CallMethod(Stream stream){ return string.Empty;}CallMethod的返回string类型派生自委托类型的object,合乎协变性;CallMethod的参数类型Stream是委托的参数类型FileStream的基类,合乎逆变性。 不合乎协变性或逆变性的无奈和委托绑定delegate object CallBack(FileStream stream);//谬误:CallMethod返回类型谬误var callback = new CallBack(CallMethod);static int CallMethod(Stream stream){ return 0;}回调实例办法var testDel1 = new CustomDelegate(new Program().InstanceDelegate);testDel1.Invoke("回调实例办法");private void InstanceDelegate(string msg){ Console.WriteLine("msg : {0}", msg);}*回调实例办法,委托须要晓得办法操作的是哪个对象的实例 CLR如何实现委托应用ILDasm.exe查看生成的程序集,如下 通过查看IL代码能够晓得,在申明委托CallBack的时候,编译器其实会主动生成如下的一个类: internal class CallBack : MulticastDelegate{ //结构器 public CallBack(Object object, IntPtr method); //与源代码调用办法统一 public virtual void Invoke(System.IO.FileStream); //以下两个办法实现对回调办法的异步回调 public virtual IAsyncResult BeginInvoke(System.IO.FileStream, System.AsyncCallback callback, Object object); public virtual void EndInvoke(System.IAsyncResult result); }所有委托类型都派生自MulticastDelegate,所以天然继承了父类的字段、属性和办法,其中有三个公有字段尤为重要: ...

December 6, 2020 · 1 min · jiezi

关于c#:数组

概念数组是一个存储雷同数据类型的固定大小的程序汇合,容许将多个数据项当作一个汇合来解决的数据结构。 数组的申明//dataType[] arrayNameint[] intArray;//初始化intArray = new int[3];第一行代码申明了一个int类型的数组,此时并没有调配数组,所以默认赋值为null。第二行代码将会在托管堆上调配包容3个未装箱的int值的内存块,并默认为所有值赋值为0。 援用类型数组class People { }People[] peopleArray;//全副初始化为null,未调配值,相当于创立了一组援用peopleArray = new People[3];因为数组是援用类型,所以不论是值类型数组还是援用类型数组,都是存在于托管堆中的,值类型数组和援用类型数组在托管中的状况如图: 上图的People数组,就是执行了以下代码的后果 peopleArray[0] = new Man();peopleArray[1] = new Woman();peopleArray[2] = new Child();数组类型0基数组(索引从0开始)多维数组(包含一维数组)交织数组(由数组形成的数组)申明多维数组int[,] intArrays = new int[2, 2]; //二维数组string[,,] strArrays = new string[1, 2, 2]; //三维数组申明交织数组int[][] interleavedArray = new int[3][];interleavedArray[0] = new int[1];interleavedArray[1] = new int[2];interleavedArray[2] = new int[3];将数组的申明与初始化合并int[] intArray = new int[] { 1, 2, 3 };int[,] intArrays = new int[,] { { 1, 2 } };//二维//简化var intArray = new int[] { 1, 2, 3 };//持续简化var intArray = new[] { 1, 2, 3 };*在应用隐式类型的数组性能时(不指定数组的具体类型),编译器会查看用于初始化数组元素的类型,并抉择所有元素最靠近的独特基类作为数组的类型,如果其中某一个元素与其它不具备雷同类型或基类型编译器将报错:找不到隐式类型数组的最佳类型。 ...

December 5, 2020 · 2 min · jiezi

关于c#:chap03使用线程池

1、using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading; namespace DataReport{ class Class1{ static void Main(string[] args) { int threadId = 0; RunOnThreadPool poolDelegate = Test; var t = new Thread(() => Test(out threadId)); t.Start(); t.Join(); Console.WriteLine("Thread id :{0}", threadId); IAsyncResult r = poolDelegate.BeginInvoke(out threadId, Callback, "a delegate asynchronous call"); r.AsyncWaitHandle.WaitOne(); string result = poolDelegate.EndInvoke(out threadId, r); Console.WriteLine("Thread pool worker thread id:{0}", threadId); Console.WriteLine(result); Thread.Sleep(TimeSpan.FromSeconds(2)); } private delegate string RunOnThreadPool(out int threadId); private static void Callback(IAsyncResult ar) { Console.WriteLine("Starting a callback..."); Console.WriteLine("State passed to a callback: {0}", ar.AsyncState); Console.WriteLine("Is thread pool thread:{0}", Thread.CurrentThread.IsThreadPoolThread); Console.WriteLine("Thread pool worker thread id: {0}", Thread.CurrentThread.ManagedThreadId); } private static string Test(out int threadId) { Console.WriteLine("Starting..."); Console.WriteLine("Is thread pool thread:{0}", Thread.CurrentThread.IsThreadPoolThread); Thread.Sleep(TimeSpan.FromSeconds(2)); threadId = Thread.CurrentThread.ManagedThreadId; return string.Format("Thread pool worker thread id was {0}", threadId); }}} ...

December 4, 2020 · 2 min · jiezi

关于c#:使用线程池

应用线程池(60/217)3.1、简介3.2、在线程池中调用委托内容没看using System;using System.Threading;namespace LionelPro{ class Program { static void Main(string[] args) { int threadId = 0; RunOnThreadPool poolDelegate = Test; var t = new Thread(() => Test(out threadId)); t.Start(); t.Join(); Console.WriteLine("Thread id:{0}", threadId); IAsyncResult r = poolDelegate.BeginInvoke(out threadId, Callback, "a delegate asynchronous call"); r.AsyncWaitHandle.WaitOne(); string result = poolDelegate.EndInvoke(out threadId, r); Console.WriteLine("Thread pool worker thread id:{0}", threadId); Console.WriteLine(result); Thread.Sleep(TimeSpan.FromSeconds(2)); } private delegate string RunOnThreadPool(out int threadId); private static void Callback(IAsyncResult ar) { Console.WriteLine("Starting a callback..."); Console.WriteLine("State passed to a callback:{0}", ar.AsyncState); Console.WriteLine("Is thread pool thread:{0}", Thread.CurrentThread.IsThreadPoolThread); Console.WriteLine("Thread pool worker thread id: {0}", Thread.CurrentThread.ManagedThreadId); } private static string Test(out int threadId) { Console.WriteLine("Starting ..."); Console.WriteLine("Is thread pool thread:{0}", Thread.CurrentThread.IsThreadPoolThread); Thread.Sleep(TimeSpan.FromSeconds(2)); threadId = Thread.CurrentThread.ManagedThreadId; return string.Format("Thread pool worker thread id was:{0}", threadId); } }}3.3、向线程池中放入异步操作3.4、线程池与并行度3.5、实现一个勾销选项3.6、在线程池中应用期待事件处理3.7、应用计时器3.8、应用BackgroundWorker组件

December 4, 2020 · 1 min · jiezi

关于c#:C-WinForm-线程间操作无效-从不是创建控件的线程访问它的解决办法

.net2后是不能跨线程拜访控件的。,窗体上的控件是以后线程创立的,当用户异步执行一个办法:在该办法中给窗体上的控件赋值,记住:当执行一个异步委托的时候,其实 就是开了一个线程去执行那个办法,这样就会报错:线程间操作有效: 从不是创立控件“某某某”的线程拜访它。 1.在窗口线程中设置CheckForIllegalCrossThreadCalls = falsepublic Form1(){ InitializeComponent(); Control.CheckForIllegalCrossThreadCalls = false;}2. 利用委托private void button1_Click(object sender, EventArgs e) { new Action(show).BeginInvoke(null, null); } void show() { //异步外的办法。这样窗体不会假死 while (true) { Thread.Sleep(2000); Action ac = new Action(showText); this.Invoke(ac); //在同步办法外面实现更新窗体上的数据 } } /// <summary> /// 更新数据 /// </summary> void showText() { richTextBox1.AppendText("更新\n"); }大家能够参考下MSDN:如何:对 Windows 窗体控件进行线程平安调用 http://msdn.microsoft.com/zh-...转载:https://www.cnblogs.com/nsky/...

November 30, 2020 · 1 min · jiezi

关于c#:枚举和位标志

枚举是程序中常常应用的数据类型,应用枚举,能够让代码具备更高的可读性,易扩展性以及更容易编写等有点。同时枚举还是强类型,晋升程序的健壮性。 例如要对色彩进行辨别,在不应用枚举时,可能制订约定:定义若干个值: 0,1,2,3别离代表红,黄,蓝,绿四种色彩,然而这会减少程序的保护老本。 应用枚举可能很清晰的表明代码的用意enum Color{ Red, //红 Yellow, //黄 Blue, //蓝 Green //绿}枚举值的类型枚举值的类型能够是: byte,sbyte,short,ushort,int,uint,long,ulong。默认类型是int,自定义其它类型的枚举值类型 enum Color : byte {}//获取枚举值类型(输入System.Byte)System.Console.WriteLine(System.Enum.GetUnderlyingType(typeof(Color)));获取所有枚举值foreach (var item in (Color[])System.Enum.GetValues(typeof(Color))) System.Console.WriteLine(item);后果 应用扩大办法向枚举中增加办法public static Action Set(this Action flags, Action setAction){ return flags | setAction;}//用例var action = Action.Walk;//输入 WalkConsole.WriteLine(action.ToString());action = action.Set(Action.Run);//输入 Walk, RunConsole.WriteLine(action.ToString());位标记位标记是一种非凡的枚举类型,枚举值的存在是互斥的,位标记能够了解成是一种组合的列表,如文件的属性能够有暗藏与只读等多种。 位标记的申明 [Flags] //增加Flags标记便可申明一个位标记enum Action{ None = 0, Walk = 0x0001, Run = 0x0002, Speak = 0x0004}位标记的实例应用//申明一个行为var action = Action.None;//判断该行为是否能走 输入falseConsole.WriteLine((action & Action.Walk) != 0);Console.WriteLine((action & Action.Walk) == Action.Walk);//增加行走和奔跑行为action = action | Action.Walk | Action.Run;Console.WriteLine((action & Action.Walk) != 0);//trueConsole.WriteLine((action & Action.Run) != 0); //true//删除走的行为action = action &~ Action.Walk;Console.WriteLine((action & Action.Walk) != 0);//falseConsole.WriteLine((action & Action.Run) != 0); //true应用HasFlag办法判断枚举实例中是否存在某个标记 ...

November 28, 2020 · 1 min · jiezi

关于c#:linq-查询的结果会开辟新的内存吗

一:背景1. 讲故事 昨天群里有位敌人问:linq 查问的后果会开拓新的内存吗?如果开了,那是对原序列集外面元素的深拷贝还是仅仅拷贝其援用?其实这个问题我感觉问的挺好,很多初学 C# 的敌人或多或少都有这样的疑难,甚至有 3,4 年工作教训的敌人可能都不是很分明,这就导致在写代码的时候总是会畏手畏脚,还会莫名的揪心这样玩的话内存会不会暴涨暴跌,这一篇我就用 windbg 来帮忙敌人彻底剖析一下。 二:寻找答案1. 一个小案例这位老弟提到了是深拷贝还是浅拷贝,本意就是想问: linq 一个援用类型汇合 到底会怎么? 这里我先模仿一个汇合,代码如下: class Program { static void Main(string[] args) { var personList = new List<Person>() { new Person() { Name="jack", Age=20 }, new Person() { Name="elen",Age=25, }, new Person() { Name="john", Age=22 } }; var query = personList.Where(m => m.Age > 20).ToList(); Console.WriteLine($"query.count={query.Count}"); Console.ReadLine(); } } class Person { public string Name { get; set; } public int Age { get; set; } } ...

November 26, 2020 · 3 min · jiezi

关于c#:被-C-的-ThreadStatic-标记的静态变量都存放在哪里了

一:背景1. 讲故事前几天公号里有一位敌人留言说,你windbg玩的溜,能帮我剖析下被 ThreadStatic 润饰的变量到底寄存在哪里吗?能不能帮我挖出来????????????,其实这个问题问的挺深的,玩高级语言的敌人置信很少有接触到这个的,尽管很多敌人都晓得这个个性怎么用,当然我也没特地钻研这个,既然要答复这个问题,我得钻研钻研答复之!为了更好的普适性,先从简略的说起! 二:ThreadStatic 的用法1. 一般的 static 变量置信很多敌人在代码中都应用过 static 变量,它的好处多多,比如说我常常会用 static 去做一个过程级缓存,从而进步程序的性能,当然你也能够作为一个十分好的一级缓存,如下代码: public class Test { public static Dictionary<int, string> cachedDict = new Dictionary<int, string>(); }方才我也说到了,这是一个过程级的缓存,多个线程都看得见,所以在多线程的环境下,你须要特地留神同步的问题。要么应用锁,要么应用 ConcurrentDictionary,我感觉这也是一个思维定式,很多时候思维总是在现有根底下来修补,去亡羊补牢,而没有跳出这个思维从根基下来解决,说这么多是什么意思呢?我举一个例子: 在市面上常见的链式跟踪框架中,比如说: Zikpin,SkyWalking,会应用一些汇合去存储跟踪以后线程的一些链路信息,比如说 A -> B -> C -> D -> B -> A,惯例的思维就像下面说的一样,定义一个全局 cachedDict,而后应用各种同步机制,其实你也能够升高 cachedDict 的拜访作用域,将 全局拜访 改成 Thread级拜访,这难道不是更好的解决思路吗? 2. 用 ThreadStatic 标记 static 变量要想做到 Thread级作用域,实现起来非常简单,在 cachedDict 上打一个 ThreadStatic 个性即可,批改代码如下: public class Test { [ThreadStatic] public static Dictionary<int, string> cachedDict = new Dictionary<int, string>(); }接下来能够开多个线程给 cachedDict 灌数据,看看 dict 是不是 Thread级作用域,实现代码如下: ...

November 23, 2020 · 4 min · jiezi

关于c#:如何剔掉-sql-语句中的尾巴我用-C-苦思了五种办法

一:背景1. 讲故事这几天都在修复bug真的太忙了,期间也遇到了一个挺乏味bug,和大家分享一下,这是一块sql挺简单的报表相干业务,不晓得哪一位大佬在盘根错节的 嵌套 + 平行 if判断中sql拼接在某些UI组合下出问题了,最终的 sql 架构相似这样的。 var sql = "select 1 union all select 2 union all select 3 union all";这种sql到数据库去必定是报错的,有些敌人可能想说这还不简略,在相干的 if 判断中不要追加这个 union all 就好了,这的确是一个根治的方法,但现实情况这一块的业务太简单了,也不太敢改外面的代码,改的没问题还好,改出问题你得兜着走,所以最保险的方法就是怎么去掉 union all 这个大尾巴,所以我罗唆思考了一会,想出了如下五种方法。 二:剔除 union all 的五大形式1. 最原始的 for 循环最简略的方法就是通过 for 循环搞定,我能够倒序判断最初几个字符是不是关键词 union all 就能够了,如下代码所示: static void Main(string[] args) { var sql = "select 1 union all select 2 union all select 3 union all"; var keyword = "union all"; var isall = true; int i = 0; for (i = 1; i <= keyword.Length; i++) { if (keyword[keyword.Length - i] != sql[sql.Length - i]) { isall = false; break; } } if (isall) { var query = sql.Substring(0, sql.Length - i + 1); Console.WriteLine(query); } } ...

November 21, 2020 · 3 min · jiezi

关于c#:c-之winform-可编辑table-踩过的坑

界面图: 残缺代码: [数据库交互和一些工具类等疏忽 只看逻辑]using System;using System.Collections.Generic;using System.Configuration;using System.Data;using System.Drawing;using System.IO;using System.Reflection;using System.Text;using System.Text.RegularExpressions;using System.Web.Script.Serialization;using System.Windows.Forms;using ess_zbfz_main.commonForm;using ess_zbfz_main.dto;using ess_zbfz_main.entity;using ess_zbfz_main.ifs;using ess_zbfz_main.util;using ess_zbfz_main.vo;using ess_zbfz_main.zhaobiao;using Newtonsoft.Json;using PublicLibrary;namespace ess_zbfz_main.baseInfoFrm{ public partial class FrmBzjAdd : Form,UploadCommonIFS { private static string sqliteDbName = ConfigurationManager.AppSettings["sqliteDBName"].ToString(); //数据库名称 private static string sqliteDbLocation = ConfigurationManager.AppSettings["sqliteDBLocation"].ToString(); //数据库寄存门路 //保留接口 internal static string apiSave = "oszbsupplierdeposit/save"; //更新附件信息 internal static string apiUpdateFile = "oszbsupplierdeposit/updateFile"; //以后的我的项目信息 private OsZbPurchaseProjectInfo currentProjectInfo; //保证金信息 private OsZbSupplierDeposit currentDeposit; //保证金详情信息 private List<OsZbSupplierDepositDetail> detailList; //标下拉 private List<ComboBoxVo> markList; //点击工夫 public DateTime clickTime; //以后行 private int currentRow =0; public FrmBzjAdd() { InitializeComponent(); } public FrmBzjAdd(OsZbPurchaseProjectInfo currentProjectInfo, OsZbSupplierDeposit osZbSupplierDeposit) { this.currentProjectInfo = currentProjectInfo; this.currentDeposit = osZbSupplierDeposit; InitializeComponent(); } private void FrmBzjAdd_Load(object sender, EventArgs e) { this.supplierName.Text = PublicVo.SupplyName; this.projectName.Text = currentProjectInfo.ProjectName; this.projectNo.Text = currentProjectInfo.ProjectNo; this.listDataGriddView.AutoGenerateColumns = false; //按键 this.totalMoney2.KeyPress += Main_KeyPress; this.totalInsure.KeyPress += Main_KeyPress; //失焦事件 this.totalMoney2.LostFocus += Main_LostFocus; this.totalInsure.LostFocus += Main_LostFocus; //02物资类到标段填写,01服务类到包填写 if (currentProjectInfo!=null && currentProjectInfo.PurchaseType == "02") { this.listDataGriddView.Columns["packName"].Visible = false; } LoadData(null); } private void Main_LostFocus(object sender, EventArgs e) { try { TextBox textBox = (TextBox)sender; string value = textBox.Text; if (value != null && value.ToString().EndsWith(".")) { string valueTxt = value.Substring(0, value.Length-1); textBox.Text = valueTxt; } if (!string.IsNullOrEmpty(this.totalMoney2.Text) && !string.IsNullOrEmpty(this.totalInsure.Text)) { decimal total = Decimal.Add(Convert.ToDecimal(this.totalMoney2.Text), Convert.ToDecimal(this.totalInsure.Text)); this.total.Text = total.ToString(); } } catch (Exception ex) { MessageBox.Show(ex.Message, "提醒", MessageBoxButtons.OK, MessageBoxIcon.Warning); } } private void Main_KeyPress(object sender, KeyPressEventArgs e) { try { TextBox textBox = (TextBox)sender; int start = textBox.SelectionStart; int len = textBox.SelectionLength; string text = ""; if (len > 0) { text = textBox.Text.Substring(0, start) + e.KeyChar.ToString() + textBox.Text.Substring(start + len - 1, textBox.Text.Length - start - len); } else { text = textBox.Text + e.KeyChar.ToString(); } string pattern = @"^([1-9]\d{0,12}|0)(\.\d{0,3})?$"; if ("\b".Equals(e.KeyChar.ToString()) || "\r".Equals(e.KeyChar.ToString()) || "\t".Equals(e.KeyChar.ToString())) { return; } if (!Regex.IsMatch(text, pattern)) { e.Handled = true; } } catch (Exception ex) { MessageBox.Show(ex.Message, "提醒", MessageBoxButtons.OK, MessageBoxIcon.Warning); } } /// <summary> /// 加载数据 /// </summary> /// <param name="flag"></param> public void LoadData(string flag) { try { if(this.Owner is FrmBzj) { FrmBzj frmBzj= (FrmBzj)this.Owner; //刷新父窗口的办法 frmBzj.RefreshSelf(); } this.listDataGriddView.DataSource = null; //查问标下拉信息 string markComboboxSql = "select OS_ZB_PURCHASE_PROJECT_INFO.MARK_NO as keyValue,OS_ZB_PURCHASE_PROJECT_INFO.MARK_NAME as keyName from OS_ZB_PURCHASE_PROJECT_INFO where OS_ZB_PURCHASE_PROJECT_INFO.PROJECT_NO ='" + currentProjectInfo.ProjectNo + "' group by OS_ZB_PURCHASE_PROJECT_INFO.MARK_NO "; markList = SQLiteLibrary.SelectBySql<ComboBoxVo>(sqliteDbLocation, sqliteDbName, markComboboxSql); string defaultPattern = "yyyy-MM-dd"; DateUtil.SetDatePick(ref this.yxq, defaultPattern, true, DatePickChange); //批改页面 if (currentDeposit != null) { string mainSql = "SELECT OS_ZB_SUPPLIER_DEPOSIT.*,OS_ZB_PURCHASE_PROJECT_INFO.PROJECT_NAME,SYS_FILE_INFO.FILE_PATH FROM OS_ZB_SUPPLIER_DEPOSIT"; mainSql += " left join OS_ZB_PURCHASE_PROJECT_INFO ON OS_ZB_PURCHASE_PROJECT_INFO.PROJECT_NO =OS_ZB_SUPPLIER_DEPOSIT.PROJECT_NO"; mainSql += " left join SYS_FILE_INFO on SYS_FILE_INFO.ID =OS_ZB_SUPPLIER_DEPOSIT.ATTACH_ID "; mainSql += " where OS_ZB_SUPPLIER_DEPOSIT.id='" + currentDeposit.Id + "'"; List<OsZbSupplierDeposit> lists = SQLiteLibrary.SelectBySql<OsZbSupplierDeposit>(sqliteDbLocation, sqliteDbName, mainSql); currentDeposit = lists.Count > 0 ? lists[0] : null; if ("baodan".Equals(currentDeposit.VoucherCategory)) { currentDeposit.VoucherCategory = "保单"; } else if ("huikuan".Equals(currentDeposit.VoucherCategory)) { currentDeposit.VoucherCategory = "汇款"; } //给主页面局部设置信息 SetPageMainInfo(this.groupBox1, currentDeposit); //投保形式 不能批改 this.payWay.Enabled = false; this.AddRowBtn.Visible = currentDeposit.Sfanjn != "YES"; //上传的图片 if (!StringUtil.IsEmpty(currentDeposit.FilePath)) { currentDeposit.FilePath =LocalFileUtil.GetPath(currentDeposit.FilePath); Image image = new Bitmap(currentDeposit.FilePath); this.pictureBox1.Image =new Bitmap(image, 300, 300); } //this.pictureBox1.Image = new this.totalMoney2.Text = currentDeposit.TotalMoney; string secordSql = "select OS_ZB_SUPPLIER_DEPOSIT_DETAIL.*,OS_ZB_PURCHASE_PROJECT_INFO.MARK_NAME,'No' AS isAddRow from OS_ZB_SUPPLIER_DEPOSIT_DETAIL"; secordSql += " left join OS_ZB_SUPPLIER_DEPOSIT on OS_ZB_SUPPLIER_DEPOSIT.ID = OS_ZB_SUPPLIER_DEPOSIT_DETAIL.PARENT_ID"; secordSql += " left join OS_ZB_PURCHASE_PROJECT_INFO on OS_ZB_PURCHASE_PROJECT_INFO.PROJECT_NO = OS_ZB_SUPPLIER_DEPOSIT.PROJECT_NO and OS_ZB_SUPPLIER_DEPOSIT_DETAIL.MARK_NO = OS_ZB_PURCHASE_PROJECT_INFO.MARK_NO"; secordSql += " where OS_ZB_SUPPLIER_DEPOSIT_DETAIL.PARENT_ID = '" + currentDeposit.Id + "' group by OS_ZB_SUPPLIER_DEPOSIT_DETAIL.ID"; detailList = SQLiteLibrary.SelectBySql<OsZbSupplierDepositDetail>(sqliteDbLocation, sqliteDbName, secordSql); for (int i = 0; i < detailList.Count; i++) { detailList[i].DepositMoney = string.IsNullOrEmpty(detailList[i].DepositMoney) ? "0" : detailList[i].DepositMoney; detailList[i].TotalMoney = string.IsNullOrEmpty(detailList[i].TotalMoney) ? "0" : detailList[i].TotalMoney; detailList[i].DepositInsure = string.IsNullOrEmpty(detailList[i].DepositInsure) ? "0" : detailList[i].DepositInsure; } } else { this.panelActive.Visible = false; } //标的下拉选项 DataGridViewColumn dataGridViewColumn = this.listDataGriddView.Columns["markNo"]; if (dataGridViewColumn is DataGridViewComboBoxColumn) { DataGridViewComboBoxColumn comboBoxColum = (DataGridViewComboBoxColumn)dataGridViewColumn; ComboBoxVo comboBoxVo = new ComboBoxVo("", "请抉择"); markList.Insert(0, comboBoxVo); comboBoxColum.DataSource = markList; comboBoxColum.ValueMember = "keyName"; comboBoxColum.DisplayMember = "keyValue"; } detailList = detailList != null && detailList.Count > 0 ? detailList : new List<OsZbSupplierDepositDetail>(); detailList.Insert(0, new OsZbSupplierDepositDetail()); this.listDataGriddView.DataSource = detailList; // 移除空白项 this.listDataGriddView.DataSource = null;//必须要 detailList.RemoveAt(0); this.listDataGriddView.DataSource = detailList; if (detailList != null && detailList.Count>0) { this.listDataGriddView.Columns["packName"].DataPropertyName = "packName"; } } catch (Exception ex) { MessageBox.Show(ex.Message, "提醒", MessageBoxButtons.OK, MessageBoxIcon.Warning); } } /// <summary> /// 主页面设置值 /// </summary> /// <param name="mainControl"></param> /// <param name="currentDeposit"></param> private void SetPageMainInfo(Control mainControl, OsZbSupplierDeposit currentDeposit) { var allControls = mainControl.Controls; for (int i = 0; i < allControls.Count; i++){ if (allControls[i] is TextBox || allControls[i] is DateTimePicker || allControls[i] is ComboBox) { SetControlValueByEntity(currentDeposit, currentDeposit.GetType(), allControls[i]); } if (allControls[i] is CheckBox) { ((CheckBox)allControls[i]).Checked = currentDeposit.Sfanjn == "YES"; } } } /// <summary> /// 给控件设置值 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="t"></param> /// <param name="type"></param> /// <param name="control"></param> private void SetControlValueByEntity<T>(T t, Type type, Control control) { string propName = StringUtil.UpperCaseFirst(control.Name); BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; PropertyInfo propertyInfo = type.GetProperty(propName, bindingFlags); if (propertyInfo != null) { object value =propertyInfo.GetValue(t); control.Text = value!=null?value.ToString():null; } /* else if (propertyInfo == null && "DepositInsure".Equals(propName))//保险可为0 { propertyInfo.SetValue(t, "0"); }*/ } /// <summary> /// 全选和全不选 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btnAllCheck_Click(object sender, EventArgs e) { string tag = this.btnAllCheck.Tag.ToString(); //完结编辑 this.listDataGriddView.EndEdit(); bool check = false; //全选 if (tag == "checkAll") { check = true; } int count = Convert.ToInt16(listDataGriddView.Rows.Count.ToString()); for (int i = 0; i < count; i++) { DataGridViewCheckBoxCell selectCheckCell = (DataGridViewCheckBoxCell)listDataGriddView.Rows[i].Cells["select_check"]; //bool flag = Convert.ToBoolean(selectCheckCell.Value); selectCheckCell.Value = check; } // if (tag == "checkAll") { this.btnAllCheck.Text = "全不选"; this.btnAllCheck.Tag = "unAllcheck"; this.btnAllCheck.Image = Properties.Resources.all_uncheck_20; this.btnAllCheck.Width += 6; } else { this.btnAllCheck.Text = "全选"; this.btnAllCheck.Tag = "checkAll"; this.btnAllCheck.Image = Properties.Resources.all_check_20; this.btnAllCheck.Width -= 6; } } /// <summary> /// 删除性能 --- UI删除行 不操作数据库 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btnDelete_Click(object sender, EventArgs e) { try { int count = Convert.ToInt16(listDataGriddView.Rows.Count.ToString()); //物理新增的行 List<int> deleteRows = new List<int>(); //绑定数据源的行 List<OsZbSupplierDepositDetail> dataSourceRows = new List<OsZbSupplierDepositDetail>(); for (int i = 0; i < count; i++) { if ((bool)listDataGriddView.Rows[i].Cells[0].EditedFormattedValue == true) { if (detailList!=null && detailList.Count> i) { dataSourceRows.Add(detailList[i]); } else { deleteRows.Add(i); } } } if (deleteRows.Count <= 0 && dataSourceRows.Count<=0) { MessageBox.Show("请抉择须要删除的数据", "提醒", MessageBoxButtons.OK, MessageBoxIcon.Warning); } for (int i = 0; i < deleteRows.Count; i++) { //this.listDataGriddView.Rows. this.listDataGriddView.Rows.RemoveAt(deleteRows[i]); } for (int i = 0; i < dataSourceRows.Count; i++) { detailList.Remove(dataSourceRows[i]); } if (dataSourceRows.Count > 0) { this.listDataGriddView.DataSource = null;//必须要 this.listDataGriddView.DataSource = detailList; } //计算 CalMoney(-1); } catch (Exception ex) { MessageBox.Show("刪除异样,错误信息:" + ex.Message, "提醒", MessageBoxButtons.OK, MessageBoxIcon.Warning); } } //刷新 private void btnRefesh_Click(object sender, EventArgs e) { LoadData(null); } /// <summary> /// 新增行事件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void AddRowBtn_Click(object sender, EventArgs e) { object dataSource = this.listDataGriddView.DataSource; this.listDataGriddView.Enabled = false; //this.listDataGriddView.AllowUserToAddRows = true; //如果绑定了数据源 须要先勾销绑定 if (dataSource is List<OsZbSupplierDepositDetail>) { List<OsZbSupplierDepositDetail> detailList =(List<OsZbSupplierDepositDetail>)this.listDataGriddView.DataSource; OsZbSupplierDepositDetail detail = new OsZbSupplierDepositDetail(); detailList.Add(detail); this.listDataGriddView.DataSource = null; this.listDataGriddView.DataSource = detailList; } else { this.listDataGriddView.Rows.Add();//新增行 } this.listDataGriddView.Enabled = true; } /// <summary> /// 计算金额局部 /// </summary> private void CalMoney(int curRow) { try { int rowCount = this.listDataGriddView.Rows.Count; //行--保证金总额 Decimal rowTotal = new Decimal(); //顶部统计 保证金总额 保险总额 总金额 Decimal totalBzj = new Decimal(); Decimal totalBx = new Decimal(); Decimal total = new Decimal(); for (int i = 0; i < rowCount; i++) { rowTotal = AddCalByRows(this.listDataGriddView.Rows[i].Cells["depositMoney"], this.listDataGriddView.Rows[i].Cells["depositInsure"]); totalBzj = Decimal.Add(totalBzj, GetFormateValue(this.listDataGriddView.Rows[i].Cells["depositMoney"])); totalBx = Decimal.Add(totalBx, GetFormateValue(this.listDataGriddView.Rows[i].Cells["depositInsure"])); total = Decimal.Add(total, rowTotal); //扭转事件的触发行 【不须要设置curRow写-1】 if (curRow == i) { this.listDataGriddView.Rows[i].Cells["totalMoney"].Value = rowTotal; } } this.totalMoney2.Text = totalBzj.ToString(); this.totalInsure.Text = totalBx.ToString(); this.total.Text = total.ToString(); } catch (Exception ex) { MessageBox.Show(ex.Message, "提醒", MessageBoxButtons.OK, MessageBoxIcon.Warning); //throw; } } /// <summary> /// 计算两个单元格值的和 /// </summary> /// <param name="cell1"></param> /// <param name="cell2"></param> /// <returns></returns> private decimal AddCalByRows(DataGridViewCell cell1, DataGridViewCell cell2) { return Decimal.Add(GetFormateValue(cell1), GetFormateValue(cell2)); } /// <summary> /// 设置单元格的值 /// </summary> /// <param name="cell"></param> /// <returns></returns> private decimal GetFormateValue(DataGridViewCell cell) { Decimal val1 = Decimal.Zero; if (cell.Value != null) { val1 = Convert.ToDecimal(cell.Value.ToString()); } return val1; } //单元格批改结束 private void listDataGriddView_CellEndEdit(object sender, DataGridViewCellEventArgs e) { try { if (e.RowIndex < 0 || e.ColumnIndex<0) { return; } //计算 CalMoney(e.RowIndex); if (this.listDataGriddView.Columns[e.ColumnIndex].Name == "markNo") { DataGridViewCell dataGridViewCell = this.listDataGriddView.CurrentRow.Cells["markNo"]; object o = dataGridViewCell.Value; int markNoIndex =this.listDataGriddView.Columns["markName"].Index; this.listDataGriddView.CurrentRow.Cells["markName"].Value = o; this.listDataGriddView.UpdateCellValue(markNoIndex, e.RowIndex);// 强制更新这个单元格的数据 string markNo = ""; if (dataGridViewCell is DataGridViewComboBoxCell) { DataGridViewComboBoxCell.ObjectCollection objectCollection = ((DataGridViewComboBoxCell)dataGridViewCell).Items; for (int i = 0; i < objectCollection.Count; i++) { if (objectCollection[i] is ComboBoxVo && ((ComboBoxVo)objectCollection[i]).KeyName== o) { markNo = ((ComboBoxVo)objectCollection[i]).KeyValue; this.listDataGriddView.CurrentRow.Cells["markNo_R"].Value = markNo; } } } if (o != null && o.ToString() != null && !"请抉择".Equals(o.ToString())) { //分标名称 //查问标下拉信息 //+ " and OS_ZB_PURCHASE_PROJECT_INFO.SIGN_UP='YES' string packComboboxSql = "select OS_ZB_PURCHASE_PROJECT_INFO.PACK_NO as keyName,OS_ZB_PURCHASE_PROJECT_INFO.PACK_NAME as keyValue from OS_ZB_PURCHASE_PROJECT_INFO where OS_ZB_PURCHASE_PROJECT_INFO.MARK_NO ='" + markNo + "' order by PACK_NAME"; List<ComboBoxVo> packList = SQLiteLibrary.SelectBySql<ComboBoxVo>(sqliteDbLocation, sqliteDbName, packComboboxSql); DataGridViewColumn column = this.listDataGriddView.Columns["packName"]; if (column is DataGridViewComboBoxColumn) { DataGridViewComboBoxCell boxCell = new DataGridViewComboBoxCell(); DataGridViewComboBoxColumn comboBoxColum = (DataGridViewComboBoxColumn)column; List<string> pklist = new List<string>(); for (int i = 0; i < packList.Count; i++) { pklist.Add(packList[i].KeyValue); } if(pklist!=null && pklist.Count > 0) { pklist.Insert(0, "请抉择"); } else { pklist.Insert(0, "暂无数据"); } boxCell.DataSource = pklist; //boxCell.Value = e.RowIndex< detailList.Count?detailList[e.RowIndex].PackName:""; //分包信息 this.listDataGriddView.CurrentRow.Cells[3] = boxCell; } } } } catch (Exception ex) { MessageBox.Show(ex.Message, "提醒", MessageBoxButtons.OK, MessageBoxIcon.Warning); } } /// <summary> /// 保留提交操作 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btnSave_Click(object sender, EventArgs e) { R result = null; //完结编辑 this.listDataGriddView.EndEdit(); this.btnSave.Focus(); //this.totalMoney2.LostFocus; try { //主键id string primaryKey = System.Guid.NewGuid().ToString("N"); //批改 if (currentDeposit != null && currentDeposit.Id!=null) { primaryKey = currentDeposit.Id; } var controls = this.groupBox1.Controls; OsZbSupplierDeposit osZbSupplierDeposit = new OsZbSupplierDeposit(); for (int i = 0; i < controls.Count; i++) { if (controls[i] is TextBox || controls[i] is ComboBox || controls[i] is DateTimePicker) { SetValueByControl(osZbSupplierDeposit, osZbSupplierDeposit.GetType(), controls[i]); } } osZbSupplierDeposit.SupplierId = PublicVo.SupplyId; osZbSupplierDeposit.Id = primaryKey; osZbSupplierDeposit.TotalMoney = this.totalMoney2.Text; osZbSupplierDeposit.Sfanjn = this.sfanjn.Checked ? "YES" : "NO"; if (currentDeposit != null && currentDeposit.Id != null) { osZbSupplierDeposit.AttachId = currentDeposit.AttachId; } List<OsZbSupplierDepositDetail> detailList = GetDataGridInfo(primaryKey,true); if(osZbSupplierDeposit.Remark != null && osZbSupplierDeposit.Remark.Length > 500) { MessageBox.Show("备注内容长度最大为500个字符", "提醒", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } if (osZbSupplierDeposit.Sfanjn!="YES" && detailList.Count <= 0) { MessageBox.Show("至多须要填写一条详情数据", "提醒", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } //验证 MessageInfo<OsZbSupplierDepositDetail> messageInfo = VerifyUtil.Verify(detailList, "baozhengjin", true, ""); if (osZbSupplierDeposit.Sfanjn == "YES") { MessageInfo<OsZbSupplierDeposit> verifyMain = VerifyUtil.Verify(osZbSupplierDeposit, "baozhengjin"); if (verifyMain.ExistError) { messageInfo.ExistError = true; messageInfo.ErrorInfo = verifyMain.ErrorInfo+"\n"+messageInfo.ErrorInfo; } } Dictionary<string, string> checkRepeat = new Dictionary<string, string>(); StringBuilder sbfInfo = new StringBuilder(); string checkField1 = ""; string checkField2= ""; string checkMsg= currentProjectInfo.PurchaseType == "02"?"标":"包"; for (var i = 0; i < detailList.Count; i++) { //01 服务 02物资 物资类到标段填写,服务类到包填写 checkField1 = currentProjectInfo.PurchaseType == "02" ? detailList[i].MarkNo : (detailList[i].PackName=="请抉择"?"":detailList[i].PackName); checkField2 = currentProjectInfo.PurchaseType == "02" ? detailList[i].MarkNo : detailList[i].MarkNo + "-" + (detailList[i].PackName == "请抉择" ? "" : detailList[i].PackName); if (string.IsNullOrEmpty(checkField1)) { sbfInfo.Append($"第{i + 1}行 该{checkMsg}信息的未填写\n"); messageInfo.ExistError = true; } if (checkRepeat.ContainsKey(checkField2)) { sbfInfo.Append($"第{i + 1}行 该{checkMsg}信息的反复填写\n"); messageInfo.ExistError = true; } else { checkRepeat.Add(checkField2, ""); } } messageInfo.ErrorInfo += sbfInfo.ToString(); if (messageInfo.ExistError && !StringUtil.IsBlack(messageInfo.ErrorInfo)) { MessageBox.Show(messageInfo.ErrorInfo, "提醒", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } osZbSupplierDeposit.ListData = detailList; result = WebRequestUtil.PostBasicEntityDataApi(apiSave, osZbSupplierDeposit); if (!result.Successful) { MessageBox.Show(result.ResultHint, "提醒", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } string mainSql = ""; //批改 if (currentDeposit != null && currentDeposit.Id != null) { mainSql = SQLiteSqlUtils.CreateUpdateSql(osZbSupplierDeposit, new string[] { "id" }); //删除副表信息 string deleteDetailSql = "delete from OS_ZB_SUPPLIER_DEPOSIT_DETAIL where OS_ZB_SUPPLIER_DEPOSIT_DETAIL.PARENT_ID='"+ primaryKey + "'"; SQLiteLibrary.ExecuteSqlByTransaction(sqliteDbLocation, sqliteDbName, new string[] { mainSql, deleteDetailSql }); if (detailList != null && detailList.Count > 0) { string insertDetailSql = SQLiteSqlUtils.CreateInsertSql(detailList); SQLiteLibrary.insertData(sqliteDbLocation, sqliteDbName, insertDetailSql); } } else { //新增 mainSql = SQLiteSqlUtils.CreateInsertSql(osZbSupplierDeposit); SQLiteLibrary.insertData(sqliteDbLocation, sqliteDbName, mainSql); if (detailList!=null && detailList.Count > 0) { string insertDetailSql = SQLiteSqlUtils.CreateInsertSql(detailList); SQLiteLibrary.insertData(sqliteDbLocation, sqliteDbName,insertDetailSql); } } MessageBox.Show("保留胜利", "提醒", MessageBoxButtons.OK, MessageBoxIcon.Information); LoadData(null); this.Hide(); this.Close(); } catch (Exception ex) { MessageBox.Show(ex.Message, "提醒", MessageBoxButtons.OK, MessageBoxIcon.Warning); } } /// <summary> /// 获取datagridView的值 /// </summary> /// <returns></returns> private List<OsZbSupplierDepositDetail> GetDataGridInfo(string relPrimaryKey,bool idAuto) { List<OsZbSupplierDepositDetail> detailList = new List<OsZbSupplierDepositDetail>(); try { DataGridView dataGridView = this.listDataGriddView; BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; PropertyInfo propertyInfo = null; int rowCount = dataGridView.Rows.Count; int columCount = dataGridView.Columns.Count; OsZbSupplierDepositDetail depositDetail = null; //行 for (int i = 0; i < rowCount; i++) { depositDetail = new OsZbSupplierDepositDetail(); //列 for (int k = 0; k < columCount; k++) { SetObjValue(depositDetail, depositDetail.GetType(), dataGridView.Columns[k].Name, dataGridView.Rows[i].Cells[k]); } //设置主键的值 if (!StringUtil.IsEmpty(relPrimaryKey)) { propertyInfo = depositDetail.GetType().GetProperty("ParentId", bindingFlags); if (propertyInfo != null) { propertyInfo.SetValue(depositDetail, relPrimaryKey); } } //注解主动设置 if (idAuto) { propertyInfo = depositDetail.GetType().GetProperty("Id", bindingFlags); if (propertyInfo != null) { propertyInfo.SetValue(depositDetail, System.Guid.NewGuid().ToString("N")); } } depositDetail.MarkNo = depositDetail.MarkNo_R; detailList.Add(depositDetail); } } catch (Exception ex) { MessageBox.Show(ex.Message, "提醒", MessageBoxButtons.OK, MessageBoxIcon.Warning); } return detailList; } /// <summary> /// datagridView 取值 封装成数组对象=== 一行一行的设置 /// </summary> /// <param name="depositDetail"></param> /// <param name="type"></param> /// <param name="name"></param> /// <param name="dataGridViewCell"></param> private void SetObjValue<T>(T t, Type type, string name, DataGridViewCell dataGridViewCell) { string propName = StringUtil.UpperCaseFirst(name); if (dataGridViewCell.Value != null) { string textValue = dataGridViewCell.Value.ToString(); BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; PropertyInfo propertyInfo = type.GetProperty(propName, bindingFlags); if (propertyInfo != null) { if ("DepositInsure".Equals(propName) && string.IsNullOrEmpty(textValue))//保险可为0 { propertyInfo.SetValue(t, "0"); } else { propertyInfo.SetValue(t, textValue); } } } else { if ("DepositInsure".Equals(propName))//保险可为0 { PropertyInfo propertyInfo = type.GetProperty(propName); propertyInfo.SetValue(t, "0"); } } } /// <summary> /// 给对象设置值 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="t"></param> /// <param name="type"></param> /// <param name="control"></param> private void SetValueByControl<T>(T t, Type type, Control control) { string propName = StringUtil.UpperCaseFirst(control.Name); string textValue = control.Text; BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; PropertyInfo propertyInfo = type.GetProperty(propName, bindingFlags); if (propertyInfo != null) { propertyInfo.SetValue(t, textValue); } else if (propertyInfo == null && "DepositInsure".Equals(propName))//保险可为0 { propertyInfo.SetValue(t, "0"); } } /// <summary> /// 从新定义编辑框 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void listDataGriddView_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e) { e.Control.Controls.Clear(); int colum = this.listDataGriddView.CurrentCell.ColumnIndex; string columName = this.listDataGriddView.Columns[colum].Name; if(e.Control is DataGridViewTextBoxEditingControl) { if (columName == "payTime") { DateTimePicker btn = new DateTimePicker(); e.Control.Controls.Add(btn); btn.Dock = DockStyle.Fill; btn.Cursor = Cursors.Default; btn.Format = DateTimePickerFormat.Custom; btn.CustomFormat = "yyyy-MM-dd"; TableVo tableVo = new TableVo(this.listDataGriddView.CurrentCell.RowIndex, colum); btn.Tag = tableVo;//记录编辑的行和列 btn.ValueChanged += SetCellValue; var cellValue = this.listDataGriddView.CurrentCell.Value; //btn.MaxDate = DateTime.Now; string pattern = @"\d{4}[/-]\d{1,2}[/-]\d{1,2}"; Regex regex = new Regex(pattern); var defaultValue = DateTime.Now.ToString(); defaultValue = regex.IsMatch(defaultValue) ? regex.Match(defaultValue).Groups[0].ToString() : defaultValue; this.listDataGriddView.CurrentCell.Value = cellValue != null ? cellValue : defaultValue; btn.Value = Convert.ToDateTime(this.listDataGriddView.CurrentCell.Value.ToString()); //this.listDataGriddView.Rows[].Cells[this.listDataGriddView.CurrentColumn].Value = curValue; } else if ("depositMoney".Equals(columName) || "depositInsure".Equals(columName) || "totalMoney".Equals(columName)) { DataGridViewTextBoxEditingControl dgvTxt = (DataGridViewTextBoxEditingControl)e.Control; // 赋值 //dgvTxt.Name = columName; dgvTxt.KeyPress -= Cells_KeyPress; // 移除事件 //dgvTxt.SelectAll(); dgvTxt.KeyPress += Cells_KeyPress; // 绑定到事件 //先让编辑框聚焦 dgvTxt.Focus(); //设置光标的地位到文本尾 dgvTxt.Select(dgvTxt.TextLength, 0); //滚动到控件光标处 dgvTxt.ScrollToCaret(); } else { DataGridViewTextBoxEditingControl dgvTxt = (DataGridViewTextBoxEditingControl)e.Control; // 赋值 dgvTxt.KeyPress -= Cells_KeyPress; // 移除事件 } } } /// <summary> /// 自定义的日历 扭转值事件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void SetCellValue(object sender, EventArgs e) { DateTimePicker btn = (DateTimePicker)sender; if(btn.Tag is TableVo) { TableVo tableVo = (TableVo)btn.Tag; object value = btn.Value; string curValue = ""; Console.WriteLine("以后值:"+ value); if (value != null) { string pattern = @"\d{4}[/-]\d{1,2}[/-]\d{1,2}"; Regex regex = new Regex(pattern); curValue = btn.Value.ToString(); curValue = regex.IsMatch(curValue) ? regex.Match(curValue).Groups[0].ToString() : curValue; } this.listDataGriddView.Rows[tableVo.CurrentRow].Cells[tableVo.CurrentColumn].Value = curValue; } } private void Cells_KeyPress(object sender, KeyPressEventArgs e) { DataGridViewTextBoxEditingControl dgvTxt = (DataGridViewTextBoxEditingControl)sender; int start = dgvTxt.SelectionStart; int len = dgvTxt.SelectionLength; string text = ""; if (len > 0) { text = dgvTxt.Text.Substring(0, start) + e.KeyChar.ToString() + dgvTxt.Text.Substring(start + len - 1, dgvTxt.Text.Length - start - len); } else { text = dgvTxt.Text + e.KeyChar.ToString(); } string pattern = @"^([1-9]\d{0,12}|0)(\.\d{0,3})?$"; if ("\b".Equals(e.KeyChar.ToString()) || "\r".Equals(e.KeyChar.ToString()) || "\t".Equals(e.KeyChar.ToString())) { return; } if (!Regex.IsMatch(text, pattern)) { e.Handled = true; } } /// <summary> /// 行减少事件===>多级联动 [须要把dataPropetyName值移除] /// </summary> /// <param name="sender"></param> /// <param name="ev"></param> private void listDataGriddView_RowsAdded(object sender, DataGridViewRowsAddedEventArgs ev) { if (ev.RowIndex == -1 || ev.RowCount == 0 || detailList== null) { return; } //Console.WriteLine("行数:------------" + ev.RowCount); int maxCount = detailList != null && detailList.Count > ev.RowCount ? detailList.Count : ev.RowCount; maxCount = ev.RowCount <= 1 ? ev.RowCount : maxCount; for (int i = 0; i < maxCount; i++) { string packComboboxSql = "select OS_ZB_PURCHASE_PROJECT_INFO.PACK_NO as keyName,OS_ZB_PURCHASE_PROJECT_INFO.PACK_NAME as keyValue from OS_ZB_PURCHASE_PROJECT_INFO where OS_ZB_PURCHASE_PROJECT_INFO.MARK_NO ='" + detailList[i].MarkNo + "' order by PACK_NAME"; List<ComboBoxVo> packList = SQLiteLibrary.SelectBySql<ComboBoxVo>(sqliteDbLocation, sqliteDbName, packComboboxSql); DataGridViewColumn column = this.listDataGriddView.Columns["packName"]; if (column is DataGridViewComboBoxColumn) { List<string> pklist = new List<string>(); for (int k = 0; k < packList.Count; k++) { pklist.Add(packList[k].KeyValue); } pklist.Insert(0, "请抉择"); DataGridViewComboBoxCell boxCell = new DataGridViewComboBoxCell(); boxCell.Value = detailList.Count <= currentRow ? "" : detailList[currentRow].PackName; Console.WriteLine("值:" + boxCell.Value); boxCell.DataSource = pklist; //分包信息 this.listDataGriddView.Rows[i].Cells["packName"] = boxCell; } } /* DataGridView dgv = (DataGridView)sender; Console.WriteLine("次数:------------"+ currentRow); currentRow++; //以后行 不能超过数据的最大行 if (ev.RowIndex < dgv.Rows.Count) { //&& detailList == null if (dgv.Columns[1].Name == "markNo") { string packComboboxSql = "select OS_ZB_PURCHASE_PROJECT_INFO.PACK_NO as keyName,OS_ZB_PURCHASE_PROJECT_INFO.PACK_NAME as keyValue from OS_ZB_PURCHASE_PROJECT_INFO where OS_ZB_PURCHASE_PROJECT_INFO.MARK_NO ='" + detailList[ev.RowIndex].MarkNo + "'"; List<ComboBoxVo> packList = SQLiteLibrary.SelectBySql<ComboBoxVo>(sqliteDbLocation, sqliteDbName, packComboboxSql); DataGridViewColumn column = this.listDataGriddView.Columns[2]; if (column is DataGridViewComboBoxColumn) { List<string> pklist = new List<string>(); for (int i = 0; i < packList.Count; i++) { pklist.Add(packList[i].KeyValue); } pklist.Insert(0, "请抉择"); DataGridViewComboBoxCell boxCell = new DataGridViewComboBoxCell(); boxCell.Value = detailList.Count <= currentRow ? "" : detailList[currentRow].PackName; Console.WriteLine("值:" + boxCell.Value); boxCell.DataSource = pklist; //分包信息 boxCell.Value = detailList[ev.RowIndex].PackName; this.listDataGriddView.Rows[ev.RowIndex].Cells[2] = boxCell; //detailList[ev.RowIndex].PackName; //currentRow++; } } }*/ } /// <summary> /// 单元格验证 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void listDataGriddView_CellValidated(object sender, DataGridViewCellEventArgs e) { DataGridViewColumn currentColum = this.listDataGriddView.Columns[e.ColumnIndex]; string columName= currentColum.Name; if("depositMoney".Equals(columName) || "depositInsure".Equals(columName) || "totalMoney".Equals(columName) ) { var value = this.listDataGriddView.Rows[e.RowIndex].Cells[e.ColumnIndex].Value; if(value!=null && value.ToString().EndsWith(".")) { this.listDataGriddView.Rows[e.RowIndex].Cells[e.ColumnIndex].Value = value.ToString().Substring(0, value.ToString().Length - 1); } } } /// <summary> /// 图片上传 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void button1_Click(object sender, EventArgs e) { UploadForm upload = new UploadForm(GetSelectType(), "文件|*.jpg;*.png;*bpm,*pdf;*PDF"); DialogUtil.ShowDialog(upload, this, 800, 500, new FormWindowProp(false, false, FormBorderStyle.FixedSingle)); } /// <summary> /// 下拉框信息[原经营异样名录==》变为企业信用查问报告 重大守法企业名单==》该类型删除] /// </summary> /// <returns></returns> private List<ComboBoxVo> GetSelectType() { List<ComboBoxVo> list = new List<ComboBoxVo>(); ComboBoxVo v0 = new ComboBoxVo("请抉择", ""); ComboBoxVo v1 = new ComboBoxVo("保单", "baodan", "文件|" + ConstantVo.FILE_TYPE_IMAGE_2); ComboBoxVo v3 = new ComboBoxVo("汇款", "huikuan", "文件|" + ConstantVo.FILE_TYPE_IMAGE_2); list.Add(v0); list.Add(v1); list.Add(v3); return list; } /// <summary> /// /// </summary> /// <param name="fileInfoList"></param> /// <param name="childCallBack">子页面回调办法</param> /// <returns></returns> public R CallBackUpload(List<FileInfoVo> fileInfoList, Action childCallBack) { R resultR = new R(); try { //上传完了写入数据库 FileInfoVo fileInfoVo = fileInfoList[0]; currentDeposit.AttachId = fileInfoVo.EnclosureId;//附件id currentDeposit.VoucherCategory = fileInfoVo.AttachType; SysFileInfo sysFile = new SysFileInfo(); util.ObjectUtil.CopyPop(fileInfoVo, ref sysFile); sysFile.Id = fileInfoVo.EnclosureId; //单纯的数据存储 resultR = WebRequestUtil.PostBasicEntityDataApi(apiUpdateFile, currentDeposit); if (!resultR.Successful) { MessageBox.Show(resultR.ResultHint, "提醒", MessageBoxButtons.OKCancel, MessageBoxIcon.Information); return resultR; } //附件信息 SQLiteLibrary.insertData(sqliteDbLocation, sqliteDbName, SQLiteSqlUtils.CreateInsertSql(sysFile)); SQLiteLibrary.ExcuteSql(SQLiteSqlUtils.CreateUpdateSql(currentDeposit,new string[] {"id"})); resultR.Successful = true; //从新加载数据 LoadData(null); } catch (Exception ex) { MessageBox.Show(ex.Message, "提醒", MessageBoxButtons.OK, MessageBoxIcon.Warning); return resultR; } finally { } return resultR; } /// <summary> /// 缴纳形式 选中扭转触发事件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void comboBox1_SelectedIndexChanged(object sender, EventArgs e) { ComboBox comboBox =(ComboBox)sender; this.sfanjn.Enabled = comboBox.SelectedItem.ToString() == "投保"; if(this.listDataGriddView.DataSource is List<OsZbSupplierDepositDetail>) { this.listDataGriddView.DataSource = detailList; } else { this.listDataGriddView.Rows.Clear(); this.listDataGriddView.DataSource = detailList; } //comboBox.SelectedItem.ToString() == "电汇" if (!this.sfanjn.Enabled) { this.sfanjn.Checked = false; this.yxq.Enabled = false; this.totalInsure.Text = ""; this.totalInsure.ReadOnly = true; this.totalMoney2.Text = ""; this.totalMoney2.ReadOnly = true; this.bdh.Text = ""; this.bdh.ReadOnly = true; this.listDataGriddView.Columns["depositInsure"].Visible = true; this.listDataGriddView.Columns["totalMoney"].Visible = true; this.listDataGriddView.Columns["depositMoney"].HeaderText = "总额-汇款(元)"; } if(comboBox.SelectedItem.ToString() == "电汇") { this.listDataGriddView.Columns["depositMoney"].HeaderText = "总额(元)"; this.listDataGriddView.Columns["depositInsure"].Visible = false; this.listDataGriddView.Columns["totalMoney"].Visible = false; } } private void dateTimePicker1_ValueChanged(object sender, EventArgs e) { } private void groupBox1_Enter(object sender, EventArgs e) { } /// <summary> /// 是否按年缴纳 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void sfanjn_CheckedChanged(object sender, EventArgs e) { CheckBox checkBox = (CheckBox)sender; if(checkBox.Checked && this.payWay.Text == "投保") { this.yxq.Enabled = true; this.totalInsure.ReadOnly = false; this.totalMoney2.ReadOnly = false; this.bdh.ReadOnly = false; this.AddRowBtn.Visible = false; this.btnAllCheck.Visible = false; this.btnDelete.Visible = false; if (this.listDataGriddView.DataSource is List<OsZbSupplierDepositDetail>) { this.listDataGriddView.DataSource = null; } else { this.listDataGriddView.Rows.Clear(); this.listDataGriddView.DataSource = null; } /*this.listDataGriddView.Rows.Clear(); this.listDataGriddView.DataSource = null;*/ } else { this.yxq.Enabled = false; this.totalInsure.Text = ""; this.totalInsure.ReadOnly = true; this.totalMoney2.Text = ""; this.totalMoney2.ReadOnly = true; this.bdh.Text = ""; this.bdh.ReadOnly = true; this.AddRowBtn.Visible = true; this.btnAllCheck.Visible = true; this.btnDelete.Visible = true; } } private void DatePickChange(object sender, EventArgs e) { DateTimePicker timePicker = (DateTimePicker)sender; timePicker.CustomFormat = "yyyy-MM-dd"; } private void totalMoney2_TextChanged(object sender, EventArgs e) { } private void listDataGriddView_CellClick(object sender, DataGridViewCellEventArgs e) { if(e.RowIndex <0 && e.ColumnIndex < 0) { return; } } /* /// <summary> /// 移除控件 某个注册事件 /// </summary> public void RemoveEvent(object eventObj) { KeyPressEventHandler keyPressEventHand = null; EventHandler eventHand = null; Delegate[] dels = null; if (eventObj is KeyPressEventHandler) { keyPressEventHand = (KeyPressEventHandler)eventObj; dels = keyPressEventHand.GetInvocationList(); } else if (eventObj is EventHandler) { eventHand = (EventHandler)eventObj; dels = eventHand.GetInvocationList(); } foreach (Delegate d in dels) { //失去办法名 object delObj = d.GetType().GetProperty("Method").GetValue(d, null); string funcName = (string)delObj.GetType().GetProperty("Name").GetValue(delObj, null); if (keyPressEventHand != null) { keyPressEventHand -= d as KeyPressEventHandler; } if (eventHand != null) { eventHand -= d as EventHandler; } } }*/ }}外围代码分为四块:1.加载数据 函数为 LoadData ...

November 17, 2020 · 17 min · jiezi

关于c#:客户的一个紧急bug我用了两种方式进行-C-反编译修改源码

一:背景1. 讲故事周五下午经营反馈了一个紧急bug,说客户那边一个信息列表打不开,急需解决,附带的日志文件也发过来了,看了下日志大略是这样的: 日期:2020-11-13 12:25:45,923 线程ID:[3924] 日志级别:INFO 谬误类:xxx property:[(null)] - 谬误形容:应用程序呈现了未捕捉的异样,Message:该字符串未被辨认为无效的 DateTime。; StackTrace: 在 System.DateTimeParse.Parse(String s, DateTimeFormatInfo dtfi, DateTimeStyles styles) 在 System.Data.ConstNode..ctor(DataTable table, ValueType type, Object constant, Boolean fParseQuotes) 在 System.Data.ExpressionParser.Parse() 在 System.Data.DataExpression..ctor(DataTable table, String expression, Type type) 在 System.Data.Select..ctor(DataTable table, String filterExpression, String sort, DataViewRowState recordStates) 在 System.Data.DataTable.Select(String filterExpression)从异样信息能够看到,大略就是 DataTable.Select 的时候抛出了异样,通过调用堆栈追究了下代码大略是这样的。 public Task<DataTable> QueryDataTable() { var dt = new DataTable(); dt.Columns.Add(new DataColumn("SendTime")); dt.Rows.Add(dt.NewRow()["SendTime"] = "2020/11/14"); var where = $" SendTime < #{DateTime.Now.ToString()}#"; var query = dt.Select(where).CopyToDataTable(); }大坑就在这里,绝大多数时候过滤 DataTable 能够采纳这样的写法 : SendTime < #2020/11/5#,然而客户在新加坡,全英文操作系统,而且工夫格局也不晓得设置成啥样了,我预计工夫格局蕴含了相似的 #,正好又遇到了前后缀 # ,拆分上就出错了,导致了经典的 该字符串未被辨认为无效的 DateTime 异样被抛出。 ...

November 17, 2020 · 3 min · jiezi

关于c#:C-Span-源码解读和应用实践

一:背景1. 讲故事这两天工作上太忙没有及时继续的文章产出,和大家说声道歉,前几天群里一个敌人在问什么时候能够产出 Span 的下一篇,哈哈,这就来啦!读过上一篇的敌人应该都晓得 Span 对立了 .NET 程序 栈 + 托管 + 非托管 实现了三大块内存的对立拜访,????????,而且在 .net 底层 Library 中也是一等公民的存在,很多现有的类都提供了对 Span / ReadOnlySpan 的反对。 String 对 Span / ReadOnlySpan 的反对 public sealed class String { [MethodImpl(MethodImplOptions.InternalCall)] [NullableContext(0)] public extern String(ReadOnlySpan<char> value); }StringBuilder 对 Span / ReadOnlySpan 的反对 public sealed class StringBuilder : ISerializable { public unsafe StringBuilder Append(ReadOnlySpan<char> value) { if (value.Length > 0) { fixed (char* value2 = &MemoryMarshal.GetReference(value)) { Append(value2, value.Length); } } return this; } }Int 对 Span / ReadOnlySpan 的反对 public readonly struct Int32 { public static int Parse(ReadOnlySpan<char> s, NumberStyles style = NumberStyles.Integer, IFormatProvider? provider = null) { NumberFormatInfo.ValidateParseStyleInteger(style); return Number.ParseInt32(s, style, NumberFormatInfo.GetInstance(provider)); } }怎么样,这些通用 & 根底的类都在鼎力对接 Span / ReadOnlySpan,更别说简单类型了,其位置不言自明哈,接下来咱们就从 Span 自身的机制聊起。 ...

November 13, 2020 · 3 min · jiezi

关于c#:一个-Task-不够又来一个-ValueTask-真的学懵了

一:背景1. 讲故事前几天在我的项目中用 MemoryStream 的时候意外发现 ReadAsync 办法多了一个返回 ValueTask 的重载,真是日了狗了,一个 Task 曾经够学了,又来一个 ValueTask,晕,办法签名如下: public class MemoryStream : Stream { public override ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken = default(CancellationToken)) { } }既然是新玩意,我就比拟好奇,看看这个 ValueTask 是个啥玩意,翻翻源码看看类定义: public readonly struct ValueTask<TResult> : IEquatable<ValueTask<TResult>> { }原来是搞了一个 值类型的Task,有数的优化教训通知我,值类型相比援用类型要节俭空间的多,不信的话能够用 windbg 去校验一下,别离在 List 中灌入 1000 个Task 和 1000 个 ValueTask,看看所占空间大小。 0:000> !clrstack -lOS Thread Id: 0x44cc (0) Child SP IP Call Site0000004DA3B7E630 00007ffaf84329a6 ConsoleApp2.Program.Main(System.String[]) [E:\net5\ConsoleApp1\ConsoleApp2\Program.cs @ 17] LOCALS: 0x0000004DA3B7E6E8 = 0x000001932896ac78 0x0000004DA3B7E6E0 = 0x000001932897e7000:000> !objsize 0x000001932896ac78sizeof(000001932896AC78) = 80056 (0x138b8) bytes (System.Collections.Generic.List`1[[System.Threading.Tasks.Task`1[[System.Int32, System.Private.CoreLib]], System.Private.CoreLib]])0:000> !objsize 0x000001932897e700sizeof(000001932897E700) = 16056 (0x3eb8) bytes (System.Collections.Generic.List`1[[System.Threading.Tasks.ValueTask`1[[System.Int32, System.Private.CoreLib]], System.Private.CoreLib]])下面的代码能够看出, 1000 个 Task 需占用 80056 byte,1000 个 ValueTask 需占用 16056 byte,相差大略 5 倍,空间利用率的确失去了大大晋升,除了这个, ValueTask 还想解决什么问题呢? ...

November 10, 2020 · 3 min · jiezi

关于c#:C-中的-ref-已经被放开或许你已经不认识了

一:背景1. 讲故事最近在翻 netcore 源码看,发现框架中有不少的代码都被 ref 给润饰了,我去,这还是我意识的 ref 吗?就拿 Span 来说,代码如下: public readonly ref struct Span<T> { public ref T GetPinnableReference() { ref T result = ref Unsafe.AsRef<T>(null); if (_length != 0) { result = ref _pointer.Value; } return ref result; } public ref T this[int index] { get { return ref Unsafe.Add(ref _pointer.Value, index); } } }是不是到处都有 ref,在 struct 上有,在 local variable 也有,在 办法签名处 也有,在 办法调用处 也有,在 属性 上也有, 在 return处 也有,几乎是包罗万象,太????????啦,那这一篇咱们就来聊聊这个奇葩的 ref。 ...

November 7, 2020 · 3 min · jiezi

关于c#:一路踩坑被迫聊聊-C-代码调试技巧和远程调试

一:背景1. 讲故事每次我的项目预交付的时候,总会遇到各种奇葩的坑,我感觉有必要梳理一下以及如何疾速解决的,让起初人避避坑,这篇就聊聊本人的所闻所遇: 我去,本地环境代码跑的哧溜,上了测试环境出问题我去, 第三方提供的 dll 跑出 bug 了二:两个大坑的解决方案1. 本地环境没问题,上了测试出问题置信很多敌人都有我这样相似的遭逢,明明程序代码,配置文件都一样,挪了一个窝就出问题,你说气人不,既然问题出了那怎么疾速解决呢? 对,就是用调试,但程序部署在 centos 上,送一个 visualstudio 下来也不事实,在这种限制级条件下还想调试怎么办呢?不错,能够上近程调试,而后就很快查到了测试机器中的某一个环境变量搞错了,事件的前因后果搞清楚了,接下来就看看怎么实现 local 到 centos 的 近程调试。 1) 测试代码为了不便演示,我就在 Action 中读取 strategy 环境变量。 public class HomeController : Controller { public IActionResult Index() { ViewBag.strategy = Environment.GetEnvironmentVariable("strategy"); return View(); } }2) 装置 SSH要近程调试,须要在远端机装置 SSH,因为前面附加过程调试 就要借助 SSH 买通。 yum install openssh-server unzip curl装置实现后,就能看到 22 端口已启动 [root@localhost data]# netstat -tlnpActive Internet connections (only servers)Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1126/sshd tcp 0 0 127.0.0.1:631 0.0.0.0:* LISTEN 3037/cupsd tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN 1739/master tcp6 0 0 :::22 :::* LISTEN 1126/sshd tcp6 0 0 ::1:631 :::* LISTEN 3037/cupsd tcp6 0 0 ::1:25 :::* LISTEN 1739/master 3) 程序的公布配置公布配置上,第一个要确保是 debug 版本,第二个要确保是 可移植模式 (Portable), 如下图: ...

November 4, 2020 · 2 min · jiezi

关于c#:把-Console-部署成-Windows-服务四种方式总有一款适合你

一:背景1. 讲故事上周有一个我的项目交付,因为是医院级我的项目须要在客户的局域网独立部署。 程序: netcore 2.0,操作系统: windows server 2012,坑爹的事件就来了, netcore sdk 始终装不上,网上找了材料说须要先装置 Visual C++ Redistributable for Visual Studio 2015, 开开心心下载下来又是装置失败,再次找材料说要打一堆 零碎补丁,搞了一天!!!???????????? 环境总算是装好了,因为是 Console 服务程序,还得给它做成 windows service,看公司以前的部署形式都是采纳 vs 的 windows service 模板,如下图: 怎么说呢,这种形式太老旧了,这篇就来聊聊除了这种还有其余三种很有意思的服务部署形式,罗唆拿在一起比拟比拟吧! 2. 测试代码为了能更加正规化一些,我在 Console 中监听 Ctrl + C 事件,代码如下: public class Program { public static void Main(string[] args) { var dir = AppDomain.CurrentDomain.BaseDirectory; var cts = new CancellationTokenSource(); var bgtask = Task.Factory.StartNew(() => { TestService.Run(cts.Token); }); Console.CancelKeyPress += (s, e) => { TestService.Log($"{DateTime.Now} 后盾测试服务,筹备进行资源清理!"); cts.Cancel(); bgtask.Wait(); TestService.Log($"{DateTime.Now} 祝贺,Test服务程序已失常退出!"); }; TestService.Log($"{DateTime.Now} 后端服务程序失常启动!"); bgtask.Wait(); } }有了这个模板,再定义一个 TestService,用于一直的执行后台任务,代码如下: ...

November 2, 2020 · 3 min · jiezi

关于c#:对精致码农大佬的-理解-volatile-关键字-文章结论的思考和寻找真相

一:背景1. 讲故事昨天在园里的编辑头条看到 粗劣码农大佬 写的一篇题为:[C#.NET 拾遗补漏]10:了解 volatile 关键字 (https://www.cnblogs.com/willi... 的文章,大略就是说在 多线程环境下,一个在debug不呈现,在release中呈现的bug,原文代码如下: public class Worker{ private bool _shouldStop; public void DoWork() { bool work = false; // 留神:这里会被编译器优化为 while(true) while (!_shouldStop) { work = !work; // do sth. } Console.WriteLine("工作线程:正在终止..."); } public void RequestStop() { _shouldStop = true; }}public class Program{ public static void Main() { var worker = new Worker(); Console.WriteLine("主线程:启动工作线程..."); var workerTask = Task.Run(worker.DoWork); // 期待 500 毫秒以确保工作线程已在执行 Thread.Sleep(500); Console.WriteLine("主线程:申请终止工作线程..."); worker.RequestStop(); // 待待工作线程执行完结 workerTask.Wait(); //workerThread.Join(); Console.WriteLine("主线程:工作线程已终止"); }}文中剖析这个bug是因为在 release 环境下,jit做了 while (!_shouldStop) -> while(true) 的代码优化。 ...

October 30, 2020 · 2 min · jiezi

关于c#:用-Span-对-C-进程中三大内存区域进行统一访问-太厉害了

一:背景1. 讲故事前段时间写了几篇 C# 漫文,评论留言中有很多敌人屡次提到 Span,周末抽空看了下,的确是一个十分????????的新构造,让我想到了当年的WCF,它对立了.NET下各种零散的分布式技术,包含:.NET Remoteing,WebService,NamedPipe,MSMQ,而这里的 Span 对立了 C# 过程中的三大块内存拜访,包含:栈内存, 托管堆内存, 非托管堆内存,画个图如下: 接下来就和大家具体聊聊这三大块的内存对立拜访。 二: 过程中的三大块内存解析1. 栈内存大家应该晓得办法内的局部变量是寄存在栈上的,而且每一个线程默认会被调配 1M 的内存空间,我举个例子: static void Main(string[] args) { int i = 10; long j = 20; List<string> list = new List<string>(); }下面 i,j 的值都是存于栈上,list的堆上内存地址也是存于栈上,为了看个到底,能够用 windbg 验证一下: 0:000> !clrstack -lOS Thread Id: 0x2708 (0) Child SP IP Call Site00000072E47CE558 00007ff89cf7c184 [InlinedCallFrame: 00000072e47ce558] Interop+Kernel32.ReadFile(IntPtr, Byte*, Int32, Int32 ByRef, IntPtr)00000072E47CE558 00007ff7c7c03fd8 [InlinedCallFrame: 00000072e47ce558] Interop+Kernel32.ReadFile(IntPtr, Byte*, Int32, Int32 ByRef, IntPtr)00000072E47CE520 00007FF7C7C03FD8 ILStubClass.IL_STUB_PInvoke(IntPtr, Byte*, Int32, Int32 ByRef, IntPtr)00000072E47CE7B0 00007FF8541E530D System.Console.ReadLine()00000072E47CE7E0 00007FF7C7C0101E DataStruct.Program.Main(System.String[]) [E:\net5\ConsoleApp2\ConsoleApp1\Program.cs @ 22] LOCALS: 0x00000072E47CE82C = 0x000000000000000a 0x00000072E47CE820 = 0x0000000000000014 0x00000072E47CE818 = 0x0000018015aeab10通过 clrstack -l 查看线程栈,最初三行能够显著的看到 0a -> 10, 14 -> 20 , 0xxxxxxb10 => list堆地址,除了这些简略类型,还能够在栈上调配简单类型,这里就要用到 stackalloc 关键词, 如下代码: ...

October 26, 2020 · 3 min · jiezi

关于c#:C80之后接口已经不再单纯了我懵逼了

一:背景1. 讲故事大家在通过面向对象洗礼的时候,都理解过接口,而且晓得它是一种自上而下的设计思路,举个例子,咱们电脑上都有 USB 2.0 接口,蓝牙耳机实现了它能够进行充电,移动硬盘实现了它能够在电脑端显示硬盘内容,蓝牙鼠标实现了它能够进行鼠标操控,能够看出USB插口做进去后,谁来实现谁也搞不清楚,实现者能做出什么货色,谁也不晓得,这就是接口的魅力,落实在 C# 上就是接口中那一个一个的 stub 办法,留给将来的有缘人去实现,如下代码: public interface IUsb { void Execute(); }2. 你可能会有的纳闷有些敌人可能会说,码农胡说八道,接口不光能够定义实例办法,还能够定义 属性,索引器,事件 等等。。。 如下代码: public interface IUsb { event Action<string> action; string Name { get; set; } string this[string key] { get; set; } void Execute(); }哈哈,果然是一个好问题,没错,属性,索引器和事件都能够定义在接口中,但请不要忘了,你列举的这些都是编译器层面的语法糖而已,话中有话就是你看过 编译后的 IL 代码吗? 如下图所示: 能够看到,那些所谓的语法糖在IL层面通通是办法,这就很好的解释了为啥接口中只能定义方法的起因。 3. 当初的接口真的变了然而这种均衡在 C# 8.0 中被突破,现如今的接口除了惯例的实例办法,还能够定义任何标记为 static 的字段,属性,办法,构造函数 甚至还能够是 实例办法的默认实现,这就很奇葩了。。。不得不大吼一声,????????, 参考代码如下: public interface IUsb { //常量 public const string constVal = ""; //动态字段 public static int age = 20; //动态构造函数 static IUsb() { } //默认办法实现 void Disco() { Console.WriteLine("Disco..."); } void Execute(); }这下把我搞蒙了,目前除了一些实例字段还不能定义外,其余的都没有问题了,我置信不久的未来 interface 也会把这个遗憾解决掉,/(ㄒoㄒ)/ , 这叫我如何向起初的长辈解释呀~ 搞的我当初有很多纳闷! ...

October 24, 2020 · 2 min · jiezi

关于c#:技术债-怎样简洁高效的实现多个-Enum-自由转换

一:背景1. 讲故事前段时间和共事负责一个我的项目的两个业务模块,可能大家短少沟通,导致本该定义一个 Enum 的中央后果我俩各自定义了一个,导致前面这两个 Enum 进行对接就烦了,为了不便了解,也不想让大家看这崴脚的英文拼写,我就拿 银行 举例吧。 A共事 定义的枚举 public enum BankEnum { ICBC = 1, CMSB = 2, CMBC = 3 }B共事 定义的枚举 public enum ChinaBankEnum { 中国民生银行 = 1, 中国工商银行 = 2, 中国招商银行 = 3, }这就很尬尴了,怎么将 ChinaBankEnum 转成 BankEnum 呢? 为了寻求多快好省,本篇就聊聊这个问题。 二:寻找解决办法1. 手工匹配实质上就是找两个 Enum 的 mapping 关系,人肉匹配那是最简略粗犷的,代码如下: static BankEnum ConvertToEnum(ChinaBankEnum chinaBank) { switch (chinaBank) { case ChinaBankEnum.中国工商银行: return BankEnum.ICBC; case ChinaBankEnum.中国民生银行: return BankEnum.CMSB; case ChinaBankEnum.中国招商银行: return BankEnum.CMBC; } return default(BankEnum); }看的进去,这种写法短少灵活性,作为程序员必定不能满足于此,既然是找 mapping 关系,我置信很多敌人最早据说 mapping 一词是来源于 EntityFramework ,人家在解决 table 到 model 的 mapping 采纳的是 Attribute,是不是这样,灵感就在于此,我是不是也能够应用 Attribute 来标记两个 Enum 的对应关系呢??? ...

October 21, 2020 · 2 min · jiezi

关于c#:AspNET-通过实现-IHttpModule-来修改-Http-POST-请求的请求体

需要起因在 Web 开发中,通常须要对前端(front-end)传到后端(back-end)的数据进行过滤和校验,以防备诸如 SQL 注入、XSS 注入之类的攻打。在 Java 中,通过继承 HttpServletRequestWrapper 类可从新包装以后申请(Http Request)并将其替换,它的实现如下: public class RequestWrapper extends HttpServletRequestWrapper { private String AMP = "&"; private String queryString; public RequestWrapper(HttpServletRequest request, String queryString) { super(request); this.queryString = queryString; } public String getQueryString() { String query = null; if (super.getQueryString() != null) { query = super.getQueryString() + AMP + this.queryString; } else { query = this.queryString; } return query; }}public class RequestHandler{ public void changeRequest{ RequestWrapper reqWrapper = new RequestWrapper(httpRequest, newQueryString() ); FilterChain.doFilter(reqWrapper, servletResponse); // this FilterChain guy helps to replace the old request to // new request to runtime }}然而,Asp.NET 中并没有相似的包装器实现,通常的做法是在每一个申请通过(ProcessRequest)后再进行合法性校验,它导致的问题是每个申请 Action 都须要反复调用过滤办法来过滤申请参数。这显然冗余且麻烦得不太正当。 ...

October 20, 2020 · 3 min · jiezi

关于c#:为啥-ResponseWrite-后View就不渲染了

一:背景1. 讲故事前几天群里有一位敌人聊到,为什么我在 Action 中执行一句 Response.Write 之后,后续的 View 就不出现了,如果脑子中没有画面,那就上测试代码: public class HomeController : Controller { public IActionResult Index() { Response.WriteAsync("hello world!"); return View(); } } 后果还是挺有意思的,大家都晓得,默认状况下会渲染 /Home/Index 对应的 view 页面,但这里被 Response.WriteAsync 插了一杠子,气的 view 都渲染不进去了,那接下来就来找一找 view 为啥这么怄气? 二:寻找假相1. 从 Logger 动手置信很多人都在用 aspnetcore 中的 logger 记录日志,为什么要首选这个 logger 呢?因为它在 web框架 中是一等公民的存在,毕竟底层源码各处都嵌入着这玩意哈,轻易找点代码: internal abstract class ActionMethodExecutor{ private Task ResultNext<TFilter, TFilterAsync>(ref ResourceInvoker.State next, ref ResourceInvoker.Scope scope, [Nullable(2)] ref object state, ref bool isCompleted) where TFilter : class, IResultFilter where TFilterAsync : class, IAsyncResultFilter { ResourceInvoker.ResultExecutingContextSealed resultExecutingContext3 = this._resultExecutingContext; this._diagnosticListener.BeforeOnResultExecuting(resultExecutingContext3, tfilter); this._logger.BeforeExecutingMethodOnFilter(filterType, "OnResultExecuting", tfilter); tfilter.OnResultExecuting(resultExecutingContext3); this._diagnosticListener.AfterOnResultExecuting(resultExecutingContext3, tfilter); this._logger.AfterExecutingMethodOnFilter(filterType, "OnResultExecuting", tfilter); if (this._resultExecutingContext.Cancel) { this._logger.ResultFilterShortCircuited(tfilter); this._resultExecutedContext = new ResourceInvoker.ResultExecutedContextSealed(resultExecutingContext3, this._filters, resultExecutingContext3.Result, this._instance) { Canceled = true }; goto IL_39E; } }}而且大家想想,这种写法特地奇葩,我想底层框架中的 logger 定会有所反馈,接下来在启动程序的时候采纳 WebApplication1 的模式启动,如下图: ...

October 20, 2020 · 2 min · jiezi

关于c#:C-中的-is-真的是越来越强大越来越语义化

一:背景1. 讲故事最近发现 C#7 之后的 is 是越来越看不懂了,乍一看花里胡哨的,不过当我静下心来认真研读,发现这 is 是越来越短小精悍,而且还特地语义化,那怎是一个爽字了得????,这一篇就和大家简略聊一聊。 二:C#7 之前的 is 如何应用1. 类型兼容性检测置信学过 C# 的敌人都会晓得 is 是干嘛的,而且还常常和 as 一起比拟,前者个别做兼容性检测,后者个别做兼容性转换,这里我就举个例子吧: static void Main(string[] args) { object slot = new Slot() { ClothesName = "上衣" }; if (slot is Slot) { Console.WriteLine($"slot is {nameof(Slot)}"); } if (slot is IComparable) { Console.WriteLine($"slot is {nameof(IComparable)}"); } } public class Slot : IComparable { public string ClothesName { get; set; } public int CompareTo(object obj) {return 0;} } ...

September 30, 2020 · 3 min · jiezi

关于c#:手把手教你ASPNET-Core创建-Web-API

需要通过创立“待办事项”的工作演示,咱们能够学会并把握ASP.NET Core的相干常识。 待办事项的性能如下: 获取所有待办事项按 ID 获取项增加新项更新现有项删除项创立 Web 我的项目从“文件”菜单中选择“新建”>“我的项目” 。抉择“ASP.NET Core Web 应用程序”模板,再单击“下一步” 。将我的项目命名为 Course001,而后单击“创立”。在“创立新的 ASP.NET Core Web 应用程序”对话框中,确认抉择“.NET Core”和“ASP.NET Core 3.1” 。 抉择“API”模板,而后单击“创立” 。 增加控制器右键单击 Controllers 文件夹。抉择“增加”>“新建构建项” 。抉择“蕴含读/写操作的 API 控制器”,而后抉择“增加”。取名“TodoController.cs”。抉择“增加”。using Microsoft.AspNetCore.Mvc;using System.Collections.Generic;namespace Course001.Controllers{ [Route("api/[controller]")] [ApiController] public class TodosController : ControllerBase { [HttpGet] public IEnumerable<string> Get() { return new string[] { "value1", "value2" }; } [HttpGet("{id}")] public string Get(int id) { return "value"; } [HttpPost] public void Post([FromBody] string value) { } [HttpPut("{id}")] public void Put(int id, [FromBody] string value) { } [HttpDelete("{id}")] public void Delete(int id) { } }}通过 Postman 测试 Get创立新申请。将 HTTP 办法设置为“GET”。将申请 URI 设置为 https://localhost:44342/api/todos。抉择Send。 ...

September 29, 2020 · 1 min · jiezi

关于c#:翻译c中objectvar与dynamic的区别

原文链接:Difference Between Object and Dynamic Keyword in C#Difference between var and dynamic in C# 篇一(dynamic与object的区别)咱们常常看到很多C#开发者并不能辨别object与dynamic变量。我最近也尝试在网上找相干的教程和文章,不过还是没有找到比拟好的解释。这篇文章将梳理object与dynamic区别的关键点。 总的来说,dynamic与object都不进行编译时类型查看(compile-time type checks),只有在运行时才会对变量类型进行查看,同时,dynamic和object润饰的变量都能存储任意数据类型。object是C# 1.0引入的,而dynamic是C# 4.0引入的。稍后我会讲一下为什么要引入dynamic。(明明object曾经存在了,为什么还要引入dynamic?) 上面一些要点解释了两者的次要区别 区别一Object: 对于object,编译器所给的提示信息较少。它不是编译器平安的。例子:ps: 你在对object取值/赋值时,每次都必须要显式转换为本人想要的数据类型。object a = "Rohatash Kumar";string a1 = a.ToString(); Dynamic: 编译器不显示任何提示信息。用法:dynamic a = "Rohatash Kumar";string a1 = a; 区别二Object: C# 1.0引入Dynamic: C# 4.0引入 区别三Object: 在应用object时,你必须将object转换为原始数据类型能力进行预期操作。正如区别一所示,上面是谬误示范: object a = "Rohatash Kumar";string a1 = a;因而你必须每次都要进行显式转换Dynamic: 不须要进行显示转换,但须要晓得它外部的属性和办法。(但在点操作的时候,编译器不会提醒) 区别四Object: 如果此前没有转换为适合的数据类型(即谬误的类型转换),编译器会在运行时抛出谬误。即编译的时候不会报错,而在运行(调用)的时候就会报错。例子String a = "Rohatash Kumar";object a1 = a;int b = (int)a1;ps:下面的a为string类型;a1为object类型,保留着a的正本。因而不能将a1显示转换为int类型。 ...

September 29, 2020 · 1 min · jiezi

关于c#:遍历-Dictionary你会几种方式

一:背景1. 讲故事昨天在 StackOverflow 上看到一个很乏味的问题,说: 你会几种遍历字典的形式,而后跟帖就是各种奇葩的答复,挺有意思,马上就要国庆了,娱乐娱乐吧,说说这种挺无聊的问题????????????。 二: 应用 foreach 遍历为了不便演示,先上一段测试代码: var dict = new Dictionary<int, string>() { [10] = "A10", [20] = "A20", [30] = "A30", [40] = "A40", [50] = "A50" };1. 间接 foreach dict如果要拿百分比谈话,预计有 50%+ 的小伙伴用这种形式,为啥,简略粗犷呗,其余没什么好说的,间接上代码: foreach (var item in dict) { Console.WriteLine($"key={item.Key},value={item.Value}"); } 这里的 item 是底层在 MoveNext 的过程中用 KeyValuePair 包装进去的,如果你不信的话,看下源码呗: public bool MoveNext() { while ((uint)_index < (uint)_dictionary._count) { ref Entry reference = ref _dictionary._entries[_index++]; if (reference.next >= -1) { _current = new KeyValuePair<TKey, TValue>(reference.key, reference.value); return true; } } }2. foreach 中 应用 KeyPairValue 解构方才你也看到了 item 是 KeyValuePair 类型,不过????????的是 netcore 对 KeyValuePair 进行了加强,减少了 Deconstruct 函数用来解构 KeyValuePair,代码如下: ...

September 28, 2020 · 2 min · jiezi

关于c#:技术总结c语法优化

* 1.实体类应用属性而非字段* 1.1谬误示例: * 1.2 正确实例: 其实后者的写法很简洁,看起来就很难受,当公有字段很多 ,这个类的代码量就很难看了。 * 2.扩大办法的正确应用 谬误应用形式: 类名.该静态方法 正确形式:this待办的对象 间接调用这个静态方法(不然怎么叫扩大办法?) 区别:尽管两种办法都能够失常应用,但设计的初衷是某个类办法扩大 而不是定义工具类,另外一旦该类变动空间命名正确的形式不会报错,而谬误的形式须要各处都要批改。 * 3.委托* 3.1、什么是委托从数据结构来讲,委托是和类一样是一种用户自定义类型。 委托是办法的形象,它存储的就是一系列具备雷同签名和返回回类型的办法的地址。调用委托的时候,委托蕴含的所有办法将被执行。 * 3.2、委托的定义(委托特点:1.多态性=》委托类或办法 2.很想java中的策略模式 )委托是类型,就如同类是类型一样。与类一样,委托类型必须在被用来创立变量以及类型对象之前申明。 委托的申明原型是delegate <函数返回类型> <委托名> (<函数参数>) 本文来源于:宋文超super,专属平台有csdn、思否(SegmentFault)、 简书、 开源中国(oschina),转载请注明出处。

September 22, 2020 · 1 min · jiezi

关于c#:技术总结c-之winform-datagridview操作列

datagridview在winform的框架外面就和html外面的table一样。但不同的是,原生的datagridview外面并没有操作列这个概念,默认的列类型 有下拉框、文本、按钮、图片、链接这几类,如果须要其余的款式还须要从新写。 其实大部分需要都是如图的成果,当然你应用了别的组件【不是官网自带】,可能实现如图的成果很简略 上面讲讲如图==》操作列 有多个按钮的不同实现形式 1.1 形式一using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Text;using System.Threading.Tasks;using System.Windows.Forms; namespace chao.net{ public partial class FormTest2 : Form { public FormTest2() { InitializeComponent(); } private void toolStripLabel1_Click(object sender, EventArgs e) { } private void FormTest2_Load(object sender, EventArgs e) { this.dataGridView1.AutoGenerateColumns = false;; this.dataGridView1.CellMouseClick += dataGridView1_CellMouseClick; this.dataGridView1.CellPainting += dataGridView1_CellPainting; this.dataGridView1.Rows.Add(); } /// <summary> /// 单元格重绘 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void dataGridView1_CellPainting(object sender, DataGridViewCellPaintingEventArgs e) { if (e.ColumnIndex >= 0 && e.RowIndex >= 0) { if (this.dataGridView1.Columns[e.ColumnIndex].HeaderText == "操作") { StringFormat sf = StringFormat.GenericDefault.Clone() as StringFormat;//设置重绘入单元格的字体款式 sf.FormatFlags = StringFormatFlags.DisplayFormatControl; sf.Alignment = StringAlignment.Center; sf.LineAlignment = StringAlignment.Center; sf.Trimming = StringTrimming.EllipsisCharacter; //e.PaintContent e.PaintBackground(e.CellBounds, false);//重绘边框 //设置要写入字体的大小 System.Drawing.Font myFont = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Underline, System.Drawing.GraphicsUnit.Point, ((byte)(134))); //myFon SizeF sizeDel = e.Graphics.MeasureString("删除", myFont); SizeF sizeMod = e.Graphics.MeasureString("批改", myFont); SizeF sizeLook = e.Graphics.MeasureString("查看", myFont); float fDel = sizeDel.Width / (sizeDel.Width + sizeMod.Width + sizeLook.Width); // float fMod = sizeMod.Width / (sizeDel.Width + sizeMod.Width + sizeLook.Width); float fLook = sizeLook.Width / (sizeDel.Width + sizeMod.Width + sizeLook.Width); //设置每个“按钮的边界” RectangleF rectDel = new RectangleF(e.CellBounds.Left, e.CellBounds.Top, e.CellBounds.Width * fDel, e.CellBounds.Height); RectangleF rectMod = new RectangleF(rectDel.Right, e.CellBounds.Top, e.CellBounds.Width * fMod, e.CellBounds.Height); RectangleF rectLook = new RectangleF(rectMod.Right, e.CellBounds.Top, e.CellBounds.Width * fLook, e.CellBounds.Height); e.Graphics.DrawString("删除", myFont, Brushes.Black, rectDel, sf); //绘制“按钮” e.Graphics.DrawString("批改", myFont, Brushes.Black, rectMod, sf); e.Graphics.DrawString("查看", myFont, Brushes.Black, rectLook, sf); e.Handled = true; } } } /// <summary> /// 鼠标点击事件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void dataGridView1_CellMouseClick(object sender, DataGridViewCellMouseEventArgs e) { if (e.ColumnIndex >= 0 && e.RowIndex >= 0) { Point curPosition = e.Location;//以后鼠标在以后单元格中的坐标 if (this.dataGridView1.Columns[e.ColumnIndex].HeaderText == "操作") { //this.dataGridView1.Columns[e.ColumnIndex].Add Graphics g = this.dataGridView1.CreateGraphics(); System.Drawing.Font myFont = new System.Drawing.Font("宋体", 9F, System.Drawing.FontStyle.Underline, System.Drawing.GraphicsUnit.Point, ((byte)(134))); SizeF sizeDel = g.MeasureString("删除", myFont); SizeF sizeMod = g.MeasureString("批改", myFont); SizeF sizeLook = g.MeasureString("查看", myFont); float fDel = sizeDel.Width / (sizeDel.Width + sizeMod.Width + sizeLook.Width); float fMod = sizeMod.Width / (sizeDel.Width + sizeMod.Width + sizeLook.Width); float fLook = sizeLook.Width / (sizeDel.Width + sizeMod.Width + sizeLook.Width); Rectangle rectTotal = new Rectangle(0, 0, this.dataGridView1.Columns[e.ColumnIndex].Width, this.dataGridView1.Rows[e.RowIndex].Height); RectangleF rectDel = new RectangleF(rectTotal.Left, rectTotal.Top, rectTotal.Width * fDel, rectTotal.Height); RectangleF rectMod = new RectangleF(rectDel.Right, rectTotal.Top, rectTotal.Width * fMod, rectTotal.Height); RectangleF rectLook = new RectangleF(rectMod.Right, rectTotal.Top, rectTotal.Width * fLook, rectTotal.Height); //判断以后鼠标在哪个“按钮”范畴内 if (rectDel.Contains(curPosition))//删除 MessageBox.Show("点击删除按钮"); else if (rectMod.Contains(curPosition))//批改 MessageBox.Show("点击批改按钮"); else if (rectLook.Contains(curPosition))//查看 MessageBox.Show("点击查看按钮"); } } } private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e) { } }}次要办法是:dataGridView1_CellPainting  就是从新绘制单元格。代码在FormTest2.cs外面,进入链接在最上面。 ...

September 22, 2020 · 3 min · jiezi

关于c#:你没有看错爬网页数据C-也可以像-Jquery-那样

一:背景1. 讲故事前段时间搞了一个地方性民生资讯号,资讯嘛,都是我抄你的,你抄官媒的,小市民都喜爱奇闻异事,所以就存在一个需要,如何去定向抓取奇闻异事的中央号上的新闻,其实做起来很简略,用逻辑回归即可,这篇次要探讨如何去抓取,在 C# 中大家都晓得抓取通用的库是 HtmlAgilityPack,然而这个库支流的做法是采纳 xpath 提取网页内容,这就让我很不爽了,毕竟不相熟莫名的抵制哈,像我这个年纪的码农,被 Jquery 教育了至多 5-6 年,所以必须用 类Jquery 的形式,在 python 中有 cquery 做这件事件,那在 C# 中有没有相似的形式呢? 嘿嘿,万能的 github 上还真有。。。 就是本篇介绍的 CSQuery。 二:CSQuery1. 装置github的地址: https://github.com/zone117x/C... 而后在vs中 nuget 一下即可: 2. 举几个例子所有都准备就绪了,那怎么用呢? 不焦急,我以博客园举两个例子。 1) 将首页中的 情谊连贯 提取到 如上图,要想获取这里的 友情链接几个大字,间接用 text() 必定是不行的,默认状况它会将所有的子节点的文本也会抓到,如下图: 那怎么解决呢? 能够用 jquery 提供的 contents 办法,而后在获取的所有子节点中判断是否有 文本节点,最初获取文本节点的内容即可,如下代码: 用js是搞定了,那用 CSQuery 代码怎么搞定呢?模拟呗,如下代码: static void Main(string[] args) { var jquery = CQ.CreateDocument(new WebClient().DownloadString("http://cnblogs.com")); var content = jquery["#friend_link"].Contents().Filter((dom) => { return dom.NodeType == NodeType.TEXT_NODE; }).Text(); Console.WriteLine(content); }我不晓得用 xpath 提取这样的内容麻不麻烦,不过用 jquery 形式不简略,但驾轻就熟。 ...

September 22, 2020 · 2 min · jiezi

关于c#:技术总结winform和wpf的区别-以及-项目的设计规划

一、winform和wpf的区别:1.winform 是“前后端”不拆散的,wpf是前后端拆散的。这个是winform的设计器和c#编码“耦合度”太高了,不能独立进行设计页面。如下图是wpf的构造:【具体的解释在图片外面】==》它的设计器是用xaml来写 就像html一样,但winform的设计器还是c#的属性值页面跟语言自身的关联度太高。 2. windowform的难度比wpf绝对低,因为wpf你要学习xaml的语法。3.控件自适应:wpf比windowform好太多了4.界面的UI必定是wpf难看了,前提是会写款式,它对款式比拟自在5.wpf 能够数据相似vue=>data绑定,windowform没有这样的应用,控件的值须要外部赋值能力起到wpf的这块的成果。ps:小插曲,之前写个客户端,优先想到的是易语言,而后思维逻辑调不过去,中文的控件和代码很不适应,最终放弃,当初能够。。。嘿嘿。。。 二、我的项目的设计规划1.想做一个“伪”框架【如下图】 sys【零碎文件夹】:    放 个性【相似java的个性】 公共的组件 接口 以及 公共的工具类 mapper:       搁置xml文件 主页是用于写比较复杂的查问sql 【目前不反对insert select update 等标签再嵌入其余标签或者表达式】, 目标是清晰可见sql【放在c#外面构造不是很清晰】。//可能大佬看到这里会说怎么不把业务放到服务端,应用这个客户端调用就行,因为这里是做麻利开发,数据库是应用sqlite,如果须要对接后端接口,能够应用近程调用的依据,我会把这部分放到文章最末尾端。 project:      搁置业务代码 按模块辨别 外面只有service的实现==》仿java 工具层级已有 近程调用接口的工具、excel导入导出的工具、mysql/sqlite/oracle的sql生成工具、xml解析注入工具、word生成工具等等。 纠正一下,明天偶尔看了一下b站的 一个c#客户端的我的项目教程=============================== 对于我的项目的搭建: 我的项目构造是分为三层: 【次要是层级和类库  按单个解决方案必定大于三个】 一、UI体现层,展现的界面 如我上图所示 二、BLL业务逻辑,具体业务的一组装层,对数据拜访层返回的构造做解决 【相似java的service层】 三、DAL 数据拜访层,间接操作数据库 【相似java的dao层】 四、实体模型层:Models 贯通三层,传递数据 五、辅助工具的层:Common层 所以我的项目最下面的布局须要调整,在此写这么多是为了避免老手看到 会走错路。 本文来源于:宋文超super,专属平台有csdn、思否(SegmentFault)、 简书、 开源中国(oschina),转载请注明出处。

September 21, 2020 · 1 min · jiezi

关于c#:技术总结项目开端基础设施制造造轮子-自动生成sql-导入封装

因为这个我的项目没有应用框架,应用了sqlite数据库。前面的业务可想而知会应用多少拼接sql,这就会相当麻烦 一旦数据库扭转 就要改很多货色。 所以根底的就是封装生成sql。须要应用反射和自定义的个性。 自定义个性在于“绑定数据库列名”和“绑定业务格局” 一、业务一---主动生成sql1.首先是实体对应的表:[个性--》TableNameAttr]using System;using System.Collections.Generic;using System.Text; namespace PublicLibrary.attr{ //数据库表名[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]public class TableNameAttr: Attribute{ string value; public TableNameAttr(string value) { this.Value = value; } public string Value { get => value; set => this.value = value; }}}2.其次是实体字段对应的列名:[个性--》TableFieldAttr]using System; namespace PublicLibrary.attr{ //查问 新增 批改的注解[AttributeUsage(AttributeTargets.Field, AllowMultiple = true)]public class TableFieldAttr:Attribute{ //bool是boolean 的类型 //是否存在的字段==> 针对查问 private bool isExist =true; //数据库列名 private string columName; //字符串类型 private string jdbcType; //默认值 private string value;/* //新增 批改 选着性操作的字段 ...

September 20, 2020 · 11 min · jiezi

关于c#:项目小结百度富文本的使用java版和-oracle批量新增的坑

1、【java版】百度富文本的应用 的问题 百度富文本api:http://fex.baidu.com/ueditor/ UEditor文档: http://fex.baidu.com/ueditor/ 我的项目构造: 这里不提根底的配置 ,只能比照jsp和html配置的不同 首先,在ueditor.config.js的配置项中,咱们能够看到serverUrl 在页面是jsp的我的项目 能够间接援用java版自带的controller.jsp这个文件 1.1 jsp 和html  前者应用jsp间接写配置的初始化 【比拟不便】  后者须要创立java的controller层 写接口 获取的配置文件略微比拟 麻烦 须要依据我的项目门路来判断  通过request来获取门路只适宜前后端不拆散的我的项目  如果拆散须要获取我的项目所在的门路  拼接js相对路径 加上配置地位 config.json 能力开启富文本的上传初始化controller.jsp java后端: 从代码的 new ActionEnter的办法外面 能够晓得 他是获取我的项目的原始门路 最终读取的config.json文件 【这个文件在jsp文件夹上面) 刚好我这个我的项目是前后端拆散的  我写的【前面 预计可能会改成目录的相对路径 而不是读取拼接的形式】 所有我这个我的项目外面就不能用网上那种的java写法 批改思路有两种 思路1.配置 config.json的根门路  【间接到config.json的上一级目录] 思路2:我这个是我的项目在同一个目录下 我通过session获取到只是tomcat的绝对目录 地位必定错了 ,而且contextPath也有值. 前面改为通过类目录拼接js目录+"jsp/uditorUpload"  目录明明是jsp上面,为什么要躲写个/ueditorUpload? 如同能够看此他失去的是父目录 所以 获取的xxx/jsp/这个目录。刚好门路吻合,初始化胜利。 1.2.这个我的项目的过滤链比拟多 而这个上传的接口须要动静拼接rnd参数 这个就很麻烦 还有回显图片的接口 也须要这个rnd参数 不然就会被拦挡 ,这时候咱们须要本人设置一个拦截器白名单。这个也须要针对我的项目来解决。 ...

September 20, 2020 · 1 min · jiezi

关于c#:技术总结c客户端搭建的经验和教训

   c#客户端这个搭建起来的,当然没有有wpf框架是对的 ,因为大家比拟之前都没学过 和用过 c#这个语言,可能有人说语言是互通的,这点我不反驳,但学习也须要工夫的 就像当初java我入行学了5-6个月,当初c#入门用了2周不到的工夫,当然活学活用和组件 UI这部分不怎么样。    初期的几大败笔,一没有应用框架 如mysql 这样的框架,导致还是我写了反射生成sql的工具。二、就是没有应用UI框架如CSKin。绝对它的页面会比默认的更好看些,前期调整的私聊是 如对立应用的窗体  背景色 或其余局部的色彩须要一样的 能够重写Form类,而后对立更换原有继承的类即可,节俭屡次更换 和调整的工夫。 如下图默认的款式: <br/> CSkin组件库的: <span style="color:#86ca5e;"><br/>【比照之下 原生的款式真的很丑还要调整很多参数 对于不相熟 和Ui不好的开发不是很敌对】   前面如果有工夫能够多尝试 重写局部组件的款式,做我的项目就不会花很多工夫在设置/批改款式上,比拟咱们次要以性能为主。还有就是能够写写公共的组件。能够减少代码的复用和节约工夫。以此之前写了一个组件 传入不能同一回调。他这个不像html外面的js,能够把回调函数一起传过来,那怎么弄 。办法必定是用的 写一个公共的接口 让父窗口去实现,而后这部分的页面也能在父窗口里实现了,组件局部之间调用接口的办法。就能在父窗口的实现办法外面进行回调了。当然最蠢的办法是一个个判断父窗口是哪一个,而后去调用父窗口的办法。弊病就是屡次批改组件的公共办法。 本文来源于:宋文超super,专属平台有csdn、思否(SegmentFault)、 简书、 开源中国(oschina),转载请注明出处。

September 18, 2020 · 1 min · jiezi

关于c#:基于DDD微服务的开发实战1

1 DDD是什么?DDD是畛域驱动设计,是Eric Evans于2003年提出的,离当初有17年。 2 为什么须要DDD当软件越来越简单,理论开发中,大量的业务逻辑沉积在一个巨型类中的例子不足为奇,代码的复用性和扩展性无奈失去保障。为了解决这样的问题,DDD提出了清晰的分层架构和畛域对象的概念,让面向对象的剖析和设计进入了一个新的阶段,对企业级软件开发起到了微小的推动作用。 2.1 POP,OOP,DDD是如何解决问题面向过程编程(POP),接触到需要第一步思考把需要自顶向下分解成一个一个函数。并且在这个过程中思考分层,模块化等具体的组织形式,从而合成软件的复杂度。当软件的复杂度不是很大,POP也能失去很好的成果。 面向对象编程(OOP),接触到需要第一步思考把需要分解成一个一个对象,而后每个对象增加一个一个办法和属性,程序通过各种对象之间的调用以及合作,从而实现计算机软件的性能。跟很多工程办法一样,OOP的初衷就是一种处理软件复杂度的设计办法。 畛域驱动设计(DDD),接触到需要第一步思考把需要分解成一个一个问题域,而后再把每个问题域分解成一个一个对象,程序通过各种问题域之间的调用以及合作,从而实现计算机软件的性能。DDD是解决简单中大型软件的一套卓有成效形式,现已成为支流。 2.2 POP,OOP,DDD的特点POP,无边界,软件复杂度小实用,例如“盖房子”。 OOP,以“对象”为边界,软件复杂度中实用,例如“盖小区”。 DDD,以“问题域”为边界,软件复杂度大实用,例如“盖城市”。 3 DDD的分层架构和形成因素3.1 分层架构 整个架构分为四层,其外围就是畛域层(Domain),所有的业务逻辑应该在畛域层实现,具体形容如下: 用户界面/展示层,负责向用户展示信息以及解释用户命令。 应用层,很薄的一层,用来协调利用的流动。它不蕴含业务逻辑。它不保留业务对象的状态,但它保有利用工作的进度状态。 畛域层,本层蕴含对于畛域的信息。这是业务软件的外围所在。在这里保留业务对象的状态,对业务对象和它们状态的长久化被委托给了基础设施层。 基础设施层,本层作为其余层的撑持库存在。它提供了层间的通信,实现对业务对象的长久化,蕴含对用户界面层的撑持库等作用。 3.2 形成因素实体(Entity),具备惟一ID,可能被长久化,具备业务逻辑,对应事实世界业务对象。 值对象(Value Object),不具备惟一ID,由对象的属性形容,个别为内存中的长期对象,能够用来传递参数或对实体进行补充形容。 畛域服务(Domain Service),为上层建筑提供可操作的接口,负责对畛域对象进行调度和封装,同时能够对外提供各种模式的服务。 聚合根(Aggregate Root),聚合根属于实体对象,聚合根具备全局惟一ID,而实体只有在聚合外部有惟一的本地ID,值对象没有惟一ID 工厂(Factories),次要用来创立聚合根,目前架构实际中个别采纳IOC容器来实现工厂的性能。 仓储(Repository),封装了基础设施来提供查问和长久化聚合操作。 4 小结通过本文介绍,咱们理解DDD是为解决软件复杂性而诞生,与OOP最大的区别就是划分边界的形式不一样,所以DDD自身把握起来并不会感觉简单,DDD其实是钻研将蕴含业务逻辑的ifelse语句放在哪里的学识。

September 17, 2020 · 1 min · jiezi

关于c#:虚虚实实亦假亦真的-ValueTuple绝对能眩晕你

一:背景1. 讲故事前几天在写一个api接口,须要对衣物表进行分页查问,查问的output须要返回两个信息,一个是 totalCount,一个是 clothesList,在以前我可能须要封装一个 PagedClothes 类,如下代码: public class PagedClothes { public int TotalCount { get; set; } public List<Clothes> ClothesList { get; set; } } static PagedClothes GetPageList() { return new PagedClothes() { TotalCount = 100, ClothesList = new List<Clothes>() { } }; }在 C# 7.0 之后如果感觉封装一个类太麻烦或者没这个必要,能够用快餐写法,如下代码: static (int, List<Clothes>) GetPageList() { return (10, new List<Clothes>() { }); }这里的 (int, List<Clothes>) 是什么意思呢? 懂的敌人看到 (x,y) 马上就会想到它是 .NET 引入的一个新类:ValueTuple,接下来的问题就是真的是ValueTuple吗? 用ILSpy 看看 IL 代码: ...

September 17, 2020 · 2 min · jiezi

关于c#:NET委托事件和Lambda表达式

委托委托是什么?委托是一种援用类型(其实就是一个类,继承MulticastDelegate非凡的类。),示意对具备特定参数列表和返回类型的办法的援用。 每个委托提供Invoke办法, BeginInvoke和EndInvoke异步办法 为什么须要委托?委托能够将办法(即逻辑)作为参数; 逻辑解耦,保持稳定。代码复用,保障我的项目标准。如何应用委托?如何申明、实例化和应用委托申明委托 delegate void Del(string str);static void Notify(string name){ Console.WriteLine($"Notification received for: {name}");}实例化委托 Del del1 = new Del(Notify);//C# 2.0Del del2 = Notify;调用委托 del1.Invoke("小明");del2("小明");其余应用委托 //C# 2.0应用匿名办法来申明和实例化委托Del del3 = delegate(string name){ Console.WriteLine($"Notification received for: {name}"); };//C# 3.0应用lambda表达式申明和实例化委托Del del4 = name => { Console.WriteLine($"Notification received for: {name}"); };简化开发过程,.NET 蕴含一组委托类型: Action<> 具备参数且不返回值。Func<> 具备参数且返回由参数指定的类型的值。Predicate<> 用于确定参数是否满足委托条件的状况。理论案例代码: class Program{ /// <summary> /// 申明委托 /// </summary> /// <param name="fullName"></param> private delegate void KillDelegate(string fullName); static void Main(string[] args) { //实例化委托 var killWithKnifeDelegate = new KillDelegate(KillWithKnife); Kill("郭靖", killWithKnifeDelegate); var killWithSwordDelegate = new KillDelegate(KillWithSword); Kill("黄蓉", killWithSwordDelegate); var killWithAxeDelegate = new KillDelegate(KillWithAxe); Kill("欧阳克", killWithAxeDelegate); Console.ReadKey(); } static void Kill(string fullName, KillDelegate killDelegate) { Console.WriteLine($"{fullName}遇到怪物"); //调用委托 killDelegate.Invoke(fullName); Console.WriteLine($"{fullName}增长10教训"); } static void KillWithKnife(string fullName) { Console.WriteLine($"{fullName}用刀杀怪物"); } static void KillWithSword(string fullName) { Console.WriteLine($"{fullName}用剑杀怪物"); } static void KillWithAxe(string fullName) { Console.WriteLine($"{fullName}用斧杀怪物"); }}Lambda表达式Lambda是什么?Lambda就是应用委托的更不便的语法。 ...

September 12, 2020 · 3 min · jiezi

关于c#:NET多线程ThreadThreadPoolTaskAsync与Await

.NET多线程是什么?过程与线程过程是一种正在执行的程序。 线程是程序中的一个执行流。 多线程是指一个程序中能够同时运行多个不同的线程来执行不同的工作。 .NET中的线程Thread是创立和控制线程的类。 ManagedThreadId是线程ID。 CurrentThread是获取以后正在运行的线程。 同步与异步同步是调用一旦开始,调用者必须等到办法调用返回后,能力持续后续的行为。(单线程) 异步调用一旦开始,办法调用就会立刻返回,调用者就能够持续后续的操作。(多线程) .NET中的多线程倒退次要有Thread,ThreadPool,Task Thread就是线程,须要本人调度,间接跟零碎对接,绝对治理比较复杂及效率差。 ThreadPool是Thread的一个升级版,ThreadPool是从线程池中获取线程,如果线程池中又闲暇的元素,则间接调用,如果没有才会创立,而Thread则是会始终创立新的线程,要晓得开启一个线程就算什么事都不做也会耗费大概1m的内存,是十分节约性能的。然而ThreadPool提供的接口比拟少。 Task和ThreadPool是一样的,都是从线程池中取闲暇的线程。比ThreadPool调用接口更加丰盛。目前.Net应用多线程治理,应该优先应用Task。 代码: /// <summary>/// 多线程倒退历史/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void btnHistory_Click(object sender, EventArgs e){ Console.WriteLine($"Thread start id:{Thread.CurrentThread.ManagedThreadId} time:{DateTime.Now}"); var threadStart = new ThreadStart(DoNothing); var thread = new Thread(threadStart); thread.Start(); Console.WriteLine($"Thread end id:{Thread.CurrentThread.ManagedThreadId} time:{DateTime.Now}"); Thread.Sleep(3000); Console.WriteLine($"ThreadPool start id:{Thread.CurrentThread.ManagedThreadId} time:{DateTime.Now}"); var callback = new WaitCallback(DoNothing); ThreadPool.QueueUserWorkItem(callback); Console.WriteLine($"ThreadPool end id:{Thread.CurrentThread.ManagedThreadId} time:{DateTime.Now}"); Thread.Sleep(3000); Console.WriteLine($"Task start id:{Thread.CurrentThread.ManagedThreadId} time:{DateTime.Now}"); Action action = DoNothing; Task task = new Task(action); task.Start(); Console.WriteLine($"Task end id:{Thread.CurrentThread.ManagedThreadId} time:{DateTime.Now}");}为什么须要多线程?特点: ...

September 11, 2020 · 3 min · jiezi

关于c#:终于弄明白了-SingletonTransientScoped-的作用域是如何实现的

一:背景1. 讲故事前几天有位敌人让我有工夫剖析一下 aspnetcore 中为什么向 ServiceCollection 中注入的 Class 能够做到 Singleton,Transient,Scoped,挺有意思,这篇就来聊一聊这一话题,自从 core 中有了 ServiceCollection, 再加上风行的 DDD 模式,置信很多敌人的我的项目中很少能看到 new 了,好歹 spring 十几年前就是这么干的。 二:Singleton,Transient,Scoped 根本用法剖析源码之前,我感觉有必要先介绍一下它们的玩法,为不便演示,我这里就新建一个 webapi 我的项目,定义一个 interface 和 concrete ,代码如下: public class OrderService : IOrderService { private string guid; public OrderService() { guid = $"工夫:{DateTime.Now}, guid={ Guid.NewGuid()}"; } public override string ToString() { return guid; } } public interface IOrderService { }1. AddSingleton正如名字所示它能够在你的过程中放弃着一个实例,也就是说仅有一次实例化,不信的话代码演示一下哈。 public class Startup { public void ConfigureServices(IServiceCollection services) { services.AddControllers(); services.AddSingleton<IOrderService, OrderService>(); } } [ApiController] [Route("[controller]")] public class WeatherForecastController : ControllerBase { IOrderService orderService1; IOrderService orderService2; public WeatherForecastController(IOrderService orderService1, IOrderService orderService2) { this.orderService1 = orderService1; this.orderService2 = orderService2; } [HttpGet] public string Get() { Debug.WriteLine($"{this.orderService1}\r\n{this.orderService2} \r\n ------"); return "helloworld"; } }接着运行起来屡次刷新页面,如下图: ...

September 1, 2020 · 2 min · jiezi

关于c#:论商品促销代码的优雅性

背景介绍据我所知,简直所有的互联网公司都带有和电商无关的我的项目,而且在大多数公司外面还是无足轻重的重头戏,比方京东,淘宝。既然有电商我的项目,必然会波及到商品,一旦有商品就会有各种促销流动,比方 满100减20,三八妇女节9折等等相似流动。作为一个coder怎么能力在实现产品狗的需要下,最小改变代码,最优雅的实现呢。明天菜菜不才,就D妹子的问题献丑一番。以下以.netCore c#代码为例,其余语言相似。 D妹子版本首先D妹子有一个商品的对象,商品里有一个价格的属性,价格的单位是分 class Product { //其余属性省略 public int Price { get; set; } }上面有一个满100减20的流动,在结算价格的时候代码是这样的 public int GetPrice() { Product p = new Product(); int ret = p.Price; if (p.Price >= 100*100) { ret = ret - 20 * 100; } return ret; }有问题吗?依照需要来说没有问题,而且计算的后果也正确。然而从程序艺术来说,其实很俊俏。当初又有一个全场9折的流动,凑巧有一个商品参加了以上两个流动,而且还能够叠加应用(假如流动参加的程序是先折扣后满减)。这时候D妹子的代码就变成了这样 public int GetPrice() { Product p = new Product(); //9折流动 int ret = p.Price * 90 / 100; //满减流动 if (ret >= 100 * 100) { ret = ret - 20 * 100; } return ret; }如果当初又来一个相似流动,那这块代码还须要批改,重大违反了凋谢敞开准则,而且频繁批改曾经上线的代码,bug的几率会大大增高。这也是D妹子领导骂她并且让她codereview的起因。 ...

August 25, 2020 · 3 min · jiezi

关于c#:awaitasync-我要把它翻个底朝天这回你总该明白了吧

一:背景1. 讲故事await,async 这玩意的知识点曾经被人说的烂的不能再烂了,看似没什么好说的,但我发现有不少文章还是从实践上讲述了这两个语法糖的用法,懂得还是懂,不懂的看似懂了过几天又不懂了,人生如戏全靠记是不行的哈????????????,其实实质上来说 await, async 只是编译器层面上的语法糖,在 IL 层面都会被打成原型的,所以在这个层面上意识这两个语法糖是十分有必要的。 二:从 IL 层面意识1. 应用 WebClient 下载为了不便打回原型,我先上一个例子,应用 webclient 异步下载 http://cnblogs.com 的html,代码如下: class Program { static void Main(string[] args) { var html = GetResult(); Console.WriteLine("稍等... 正在下载 cnblogs -> html \r\n"); var content = html.Result; Console.WriteLine(content); } static async Task<string> GetResult() { var client = new WebClient(); var content = await client.DownloadStringTaskAsync(new Uri("http://cnblogs.com")); return content; } } 下面的代码非常简单,能够看到异步操作没有阻塞主线程输入: 稍等... 正在下载 cnblogs -> html \r\n, 编译器层面没什么好说的 ,接下来看下在 IL 层面产生了什么? ...

August 25, 2020 · 3 min · jiezi

关于c#:内存不够用还要速度快终于找到可以基于-File-的-Cache-了

一:背景1. 讲故事18年的时候在做纯内存我的项目的过程中遇到了这么一个问题,因为一些外围数据都是飘在内存中,所以内存空间对咱们来说额定贵重,但偏偏我的项目中有些数据须要缓存,比如说须要下钻的报表上的点,基于性能的思考,不心愿采纳独立的缓存中间件,比方 redis, mongodb,毕竟再怎么滴还是要走网络io,但间接放在本机内存中也不事实,那有没有平衡于 native cache 和 cache server 之间的计划呢? 对的,就是 disk cache,毕竟 磁盘IO 的读写要远大于网络IO,更何况配的是 SSD 呢。 二: 寻找解决方案1. 检索 github有了 disk cache 这个大方向就能够去 github 上检索关键词,看看有没有相似的中间件,说实话,java的倒不少,比方驰名的 guava,ehcache,不仅有cache的简略操作,还附带各种统计信息,刷新了对缓存认知的三观哈,尤其是 ehcache 太????????了,堆内,堆外,磁盘,分布式统统反对,用 C# 写的好不容易找到一个 disk cache 还可怜是免费的,气人哈,用 C# 调用 Java 必定不事实了哈。 2. 应用sqlite作为 disk cache既然开源社区没什么好的货色,看来只能本人封装一下了,像 ehcache 那种高阶的 diskcache 搞不定,用简略的 sqlite 作为本机的 diskcahe 还是能够的,接下来试试看。 class DiskCache { private static readonly string dbFile = $@"{Environment.CurrentDirectory}\mysqlite1.db"; private static readonly string connectionString = $@"Data Source={dbFile};Version=3"; //过期数据监测:【一分钟来一次】 private static Timer timer = new Timer((arg) => { }, null, 1000, 1000 * 60); static DiskCache() { if (!File.Exists(dbFile)) { var schema = @"CREATE TABLE Cache ( cachekey VARCHAR (1000) PRIMARY KEY NOT NULL, cachevalue TEXT NOT NULL, created DATE NOT NULL, expried DATE NOT NULL );"; using (SQLiteConnection connection = new SQLiteConnection(connectionString)) { connection.Execute(schema); } } } public static void Set<T>(string key, T value, int expiredMinutes) { using (SQLiteConnection connection = new SQLiteConnection(connectionString)) { var sql = $"delete from Cache where cachekey =@key;" + $"insert into Cache(cachekey,cachevalue,created,expried) values (@cachekey,@cachevalue,@created,@expried)"; connection.Execute(sql, new { key = key, cachekey = key, cachevalue = Newtonsoft.Json.JsonConvert.SerializeObject(value), created = DateTime.Now, expried = DateTime.Now.AddMinutes(expiredMinutes) }); } } public static T Get<T>(string key) { using (SQLiteConnection connection = new SQLiteConnection(connectionString)) { var sql = $"select cachevalue from Cache where cachekey=@cachekey and expried > @expried"; var query = connection.QueryFirstOrDefault(sql, new { cachekey = key, expried = DateTime.Now }); var json = JsonConvert.DeserializeObject<T>(query.cachevalue); return json; } } }这里有二个留神点: ...

August 23, 2020 · 2 min · jiezi

关于c#:如何校验内存数据的一致性DynamicExpresso-算是帮上大忙了

一:背景1. 讲故事记的在上一家公司做全内存我的项目的时候,因为一些要害表会在程序 startup 的时候全量灌入到内存中,但随着工夫的推移,内存和数据库的同步偶然会呈现数据差别的状况,随同着就是经营那边报过去的 bug,查看数据库的数据完整性很简略,间接写一些 sql 验证一下就好了,但校验内存中的数据就十分麻烦了,因为你不能像写 sql 一样间接去查生产中的内存汇合,那怎么办呢? 为了不便演示问题,先上一段演示代码: class Program { static void Main(string[] args) { var tradeList = new List<Trade>() { new Trade(){TradeID=1, TradeTitle="交易1", Created=Convert.ToDateTime("2020/8/1"), CustomerID=1}, new Trade(){TradeID=2, TradeTitle="交易2", Created=Convert.ToDateTime("2020/8/5"),CustomerID=2}, new Trade(){TradeID=3, TradeTitle="交易3", Created=Convert.ToDateTime("2020/8/10"), CustomerID=3} }; } } class Trade { public int TradeID { get; set; } public string TradeTitle { get; set; } public DateTime Created { get; set; } public int CustomerID { get; set; } }下面的 tradeList 就是内存中的汇合,当初有一个问题,我想查问一下 trade 表中 CustomerID in (1,2,10) && Created <= '2020-08-01' 的记录是否和内存中的 tradelist 统一。 ...

August 19, 2020 · 3 min · jiezi

关于c#:C-构造函数实例静态私有

微软官网构造函数Docs链接 每当创立类或构造时,将会调用其构造函数。 类或构造可能具备采纳不同参数的多个构造函数。 应用构造函数,程序员可能设置默认值、限度实例化,并编写灵便易读的代码。构造函数分为三种 实例构造函数公有构造函数动态构造函数修饰符public不写修饰符状况下默认(最好加上private)无修饰符(要加static)参数可自定义多个参数无参无参调用在实例化类时依据参数个数调用绝对应的实例构造函数没有实例构造函数状况下,无奈实例化类在实例化类前调用数量(1个类中)多个多个只能1个创立手动,主动(若该类中没有构造函数,则主动创立无参的实例构造函数)手动手动继承被继承时,实例化子类还会调用父类的实例构造函数无其余类型构造函数时,不能被实例化,无奈调用父类公有构造函数无奈被继承应用场景惯例应用可用于不想被继承的办法类初始化动态成员

August 14, 2020 · 1 min · jiezi

关于c#:C-构造函数实例静态私有

微软官网构造函数Docs链接 每当创立类或构造时,将会调用其构造函数。 类或构造可能具备采纳不同参数的多个构造函数。 应用构造函数,程序员可能设置默认值、限度实例化,并编写灵便易读的代码。构造函数分为三种 实例构造函数公有构造函数动态构造函数修饰符public不写修饰符状况下默认(最好加上private)无修饰符(要加static)参数可自定义多个参数无参无参调用在实例化类时依据参数个数调用绝对应的实例构造函数没有实例构造函数状况下,无奈实例化类在实例化类前调用数量(1个类中)多个多个只能1个创立手动,主动(若该类中没有构造函数,则主动创立无参的实例构造函数)手动手动继承被继承时,实例化子类还会调用父类的实例构造函数无其余类型构造函数时,不能被实例化,无奈调用父类公有构造函数无奈被继承应用场景惯例应用可用于不想被继承的办法类初始化动态成员

August 14, 2020 · 1 min · jiezi

关于c#:Enumerable-下又有新的扩展方法啦快来一起一睹为快吧

一:背景1. 讲故事前段时间将公司的一个我的项目从 4.5 降级到了 framework 4.8 ,编码的时候发现 Enumerable 中多了三个扩大办法: Append, Prepend, ToHashSet,想必玩过jquery的敌人一眼就能看出这三个办法的用处,这篇就和大家一起来聊聊这三个办法的底层源码实现,看有没有什么新货色能够挖出来。 二:Enumerable 下的新扩大办法1. Append看到这个我的第一印象就是 Add 办法, 惋惜在 Enumerable 中并没有相似的办法,可能起初程序员在这块的呼声越来越高,C#开发团队就补救了这个遗憾。 <1> 单条数据的追加接下来我写一个小例子往汇合的尾部追加一条数据,如下代码所示: static void Main(string[] args) { var arr = new int[2] { 1, 2 }; var result = Enumerable.Append(arr, 3); foreach (var item in result) { Console.WriteLine(item); } } 逻辑还是十分清晰的,再来看看底层源码是怎么实现的。 public static IEnumerable<TSource> Append<TSource>(this IEnumerable<TSource> source, TSource element){ if (source == null) { throw Error.ArgumentNull("source"); } AppendPrependIterator<TSource> appendPrependIterator = source as AppendPrependIterator<TSource>; if (appendPrependIterator != null) { return appendPrependIterator.Append(element); } return new AppendPrepend1Iterator<TSource>(source, element, appending: true);}private class AppendPrepend1Iterator<TSource> : AppendPrependIterator<TSource>{ public AppendPrepend1Iterator(IEnumerable<TSource> source, TSource item, bool appending) : base(source) { _item = item; _appending = appending; } public override bool MoveNext() { switch (state) { case 1: state = 2; if (!_appending) { current = _item; return true; } goto case 2; case 2: GetSourceEnumerator(); state = 3; goto case 3; case 3: if (LoadFromEnumerator()) { return true; } if (_appending) { current = _item; return true; } break; } Dispose(); return false; }}从下面的源码来看,这玩意做的还是挺简单的,继承关系顺次是: AppendPrepend1Iterator<TSource> -> AppendPrependIterator<TSource> -> Iterator<TSource>, 这里大家要着重看一下 MoveNext() 外面的两个办法 GetSourceEnumerator() 和 LoadFromEnumerator(),如下代码所示: ...

August 14, 2020 · 2 min · jiezi

关于c#:配置文件中的数据库连接串加密了你以为我就挖不出来吗

一:背景1. 讲故事前几天在调试物联柜终端上的一个bug时发现 app.config 中的数据库连贯串是加密的,因为调试中要切换数据库,我须要将密文放到专门的小工具上解密,改完连贯串上的数据库名,还得再加密贴到 app.config 中,烦的要死,内容如下: <appSettings> <!-- 数据库连贯字符串 --> <add key="OLEDBConnStr" value="XfES27am6Muw48iB1GlMVqvUbq7/Pp9n4XbZJsDu19YDr/Zdb3m7KT6haD7f9HLj/ZEvIiZbmSU4O5L9g03Y5IUB6KLCZI7s3nDLwTIC+bXLf5quu/r8ZAI+rgNnsNZdwoDfquRLQy5Cf2X8/MFDOcMNaZYMpTYeHsZoEERU/TP9t3n5QllJTihrmDFbiGHLqe1kfN3uB3g1kgs0oobIEfNPr09kQ/pFgzZi/kZCrK10PLZZ0pFj1YU5ReFqBsdBlecV3D2Zl3lx1Ibls24t7w==" /> </appSettings>改完bug之后,我就想这玩意能防的了谁呢? 私认为搞这么麻烦也就防防小人,像我这样的 晓人,加不加密都是等于没加密,照样给你脱库。。。???????????? 二:应用 ILSpy 去脱库1. 从DAL/Repository层去反编译代码要想得到明文的数据库连贯串,能够从代码中反推,比方从 DAL 或者 Repository 中找连贯串字段 ConnectionString,我这边的终端程序是用 wpf 写的,采纳的是经典的三层架构,所以在 bin 下能够轻松找到,如下图: 接下来用 ILSPy 反编译这个 dll。 从上图中能够看出,连贯串的明文是寄存在: OleDbHelper.ConnectionString 中的,而后能够看到,程序中定义了一个 Decrypt 办法专门用来解密连贯串,哈哈,有了这个算法,是不是就能够脱库啦??? 如下代码所示: class Program { static void Main(string[] args) { var str = "XfES27am6Muw48iB1GlMVqvUbq7/Pp9n4XbZJsDu19YDr/Zdb3m7KT6haD7f9HLj/ZEvIiZbmSU4O5L9g03Y5IUB6KLCZI7s3nDLwTIC+bXLf5quu/r8ZAI+rgNnsNZdwoDfquRLQy5Cf2X8/MFDOcMNaZYMpTYeHsZoEERU/TP9t3n5QllJTihrmDFbiGHLqe1kfN3uB3g1kgs0oobIEfNPr09kQ/pFgzZi/kZCrK10PLZZ0pFj1YU5ReFqBsdBlecV3D2Zl3lx1Ibls24t7w=="; Console.WriteLine(Decrypt(str)); } public static string Decrypt(string str) { if (!string.IsNullOrEmpty(str)) { DESCryptoServiceProvider descsp = new DESCryptoServiceProvider(); byte[] key = Encoding.Unicode.GetBytes("Oyea"); byte[] data = Convert.FromBase64String(str); MemoryStream MStream = new MemoryStream(); CryptoStream CStream = new CryptoStream(MStream, descsp.CreateDecryptor(key, key), CryptoStreamMode.Write); CStream.Write(data, 0, data.Length); CStream.FlushFinalBlock(); return Encoding.Unicode.GetString(MStream.ToArray()); } return ""; } } ...

August 12, 2020 · 2 min · jiezi

关于c#:工作十余年还是一直被问-委托和事件-有什么区别-真是够了

一:背景1. 讲故事前几天公司一个妹子问我,事件和委托有什么区别? 先由衷感叹一下,编码十余年,年老的时候常被面试官问起,当初年长了,却被后辈们时常问候,看样子逃离编码生涯之前是跑不掉了,不过奇怪的是,这个问题被问起的时候,我发现有很多人用: 事件是一种非凡的委托 来进行总结,是不是挺有意思,我想这句话可能来自于网络上的面试题答案吧,这篇我就试着彻底总结一下。 二:事件真的是非凡的委托吗?1. 猫和老鼠 经典案例要想晓得两者到底什么关系? 先得有一些根底代码,这里就用大家初学事件时用到的 猫和老鼠 经典案例,代码简化如下: class Program { static void Main(string[] args) { Cat cat = new Cat("汤姆"); Mouse mouse1 = new Mouse("杰瑞", cat); Mouse mouse2 = new Mouse("杰克", cat); cat.CatComing(); Console.ReadKey(); } } class Cat { public event Action CatCome; //申明一个事件 private string name; public Cat(string name) { this.name = name; } public void CatComing() { Console.WriteLine("猫" + name + "来了"); CatCome?.Invoke(); } } class Mouse { private string name; public Mouse(string name, Cat cat) { this.name = name; cat.CatCome += this.RunAway; //Mouse 注册 CatCome 主题 } public void RunAway() { Console.WriteLine(name + "正在逃跑"); } } ...

August 10, 2020 · 3 min · jiezi

关于c#:C用Winform制作一个简单的密码管理工具

为什么要做?首先是为了练习一下c#。想必大家都有过记不起某个平台的账号密码的经验,那种感触着实令人抓狂。那这么多账号密码基本记不住!我之前用python写过一个超级简略(连账号信息都写在代码里那种)的控制台程序用来给我提醒明码,然而我想增加一个账号时间接被麻烦到吐。 所以我才想用Winform做一个简略的小工具来帮忙我记忆。(仅供我本人应用(所以界面会比拟丑。。),然而我会把代码贴出来所以有点c#根底的其实都能够本人做一个) 构想我的需要非常简单 在我须要的时候,输出一个平台能把对应的账号密码显示进去可能增加账号信息还有一点就是在查问账号之前须要输出一个口令来验证身份,这个口令只有我本人晓得(我把它存在了app.config文件中,后续如果有须要能够扩大出更改口令的性能),所以即便他人用我的电脑运行起来这个程序,他不晓得口令也是没用的。 账号信息怎么存?我已经想要用SQL Server存,毕竟c#与它如此亲热,然而我要存的货色实质上只是一些字符串,感觉有点大材小用所以没有抉择SQL Server。最近学了JS理解了一些json的常识发现json文件是个很好的抉择于是我便决用它了。然而我还不会用c#解决json数据呀。于是我又去网上找办法,而后我就发现了newtonsoft.json(json.NET) ,它时一款.NET中开源的json序列化与反序列化工具。有了它,就能够解决我的问题了。 code首先把入口界面搭建起来,一个超级简略的窗体,只放了三个控件。 为了不便操作给它加一个退出的快捷键ESC。非常简单只须要在KeyDown事件中写下如下代码: private void Form1_KeyDown(object sender, KeyEventArgs e){ if(e.KeyCode==Keys.Escape) { this.Close(); }}而后是确定这个按钮的性能:当输出正确的口令后,点击确定能够进入到下一个界面。 口令放在哪?我将口令这个数据放在了App.config文件中,在解决方案资源管理器中右键增加新建项就能够增加它了。而后向其中退出如下代码: <appSettings> <add key="CMD" value="123123"/> </appSettings>而后给方才的入口窗体增加一个字段CMD并用ConfigurationManager将方才的配置读取进去赋值给它: public readonly string CMD=ConfigurationManager.AppSettings["CMD"].ToString() ;下面的确定按钮的性能是口令正确是将下个界面显示进去,所以咱们先把下个界面创立进去: 有了这个界面,就能够去写第一个界面中确定按钮的点击事件了: private void button1_Click(object sender, EventArgs e){ ; string entered_cmd = textBox1.Text; if(entered_cmd.Equals(CMD)) { (new GetPwd()).Show(); this.Hide(); } else { MessageBox.Show("谬误!","正告",MessageBoxButtons.OK, MessageBoxIcon.Warning); }}这样第一个界面的代码就写完了(没错就是这么简略)。 账号信息查问界面也就是下面的第二个窗体。它加载的初始状态是这样: 用于显示账号和明码的两个文本框我设置成了不可见(当输出的平台是存在的并点击确定就能够看到了)和只读。像这样: 一个小问题和上一个窗体一样,我也给这个窗体绑定了enter(相当于点击确定按钮)和esc快捷键。然而当我敞开这个窗体时,曾经无奈再进行任何操作了可是这个程序过程却没有完结。怎么解决这个问题呢?前段时间学习了委托于是我想到了一个比学校老师已经教过的更好的办法(过后还没学习委托,老师教的是把第一个窗体对象传递给第二个窗体):给第二个窗体定义一个委托字段 public Action close_main;而后在显示该窗体是将前一个窗体的close()办法传递过去即可。后面的代码批改一下: (new GetPwd() {close_main=this.Close}).Show();而后在第二个窗体的FormClosed事件中执行这个办法就能够了。 ...

August 9, 2020 · 2 min · jiezi

关于c#:CLINQ的基本用法

LINQ是什么?LINQ是Language Integrated Query(语言集成查问的缩写),微软官网对其的形容: 语言集成查问 (LINQ) 是一系列间接将查问性能集成到 C# 语言的技术统称。根本用法是什么?(我目前也只会最根本的用法。。) LINQ查问操作由三个不同的操作组成: 获取数据源创立查问执行查问上面我将用我学习时用的一个小例子来演示。有两个数据源:武林高手的汇合和武林绝学的汇合。我用的是两个汇合,实际上不只是汇合能够作为数据源微软官网文档提到: 上例中1,数据源是一个数组,因而它隐式反对泛型 IEnumerable<T> 接口。 这一事实意味着该数据源能够用 LINQ 进行查问。说回我的例子,我实现了两个类: MatialArtsMaster示意武林高手: //武林高手class MatialArtsMaster{ public int ID { get; set; } public string Name { get; set; } public int Age { get; set; } public string Menpai { get; set; } public string Kongfu { get; set; } public int Level { get; set; } public override string ToString() { return string.Format("id:{0},name:{1},age:{2},menpai:{3},kongfu:{4},level:{5}", this.ID, this.Name, this.Age, this.Menpai, this.Kongfu, this.Level); }}Kongfu 示意武林绝学: ...

August 6, 2020 · 2 min · jiezi

关于c#:用了Dapper之后通篇还是SqlConnection真的看不下去了

一:背景1. 讲故事前几天看公司一个新我的项目的底层应用了dapper,大家都晓得dapper是一个十分弱小的半自动化orm,帮程序员解决了繁琐的mapping问题,用起来十分爽,但我还是遇到了一件十分不爽的事件,如下代码所示: public class UserDAL : BaseDAL { public List<UserModel> GetList() { using (SqlConnection conn = new SqlConnection(ConnectionString)) { var list = conn.Query<UserModel>("select * from users").ToList(); return list; } } public bool Insert() { using (SqlConnection conn = new SqlConnection(ConnectionString)) { var execnum = conn.Execute("insert into xxx "); return execnum > 0; } } public bool Update() { using (SqlConnection conn = new SqlConnection(ConnectionString)) { var execnum = conn.Execute("update xxx ...."); return execnum > 0; } } } public class UserModel {}扫一下代码是不是总感觉哪里不对劲,是的,为了能应用上Dapper的扩大办法,这外面每个办法中都配上了模板化的 using (SqlConnection conn = new SqlConnection(ConnectionString)),尽管这样写逻辑上没有任何问题,但我有洁癖哈,接下来试着封装一下,嘿嘿,用更少的代码做更多的事件。 ...

August 5, 2020 · 2 min · jiezi

关于c#:用了Dapper之后通篇还是SqlConnection真的看不下去了

一:背景1. 讲故事前几天看公司一个新我的项目的底层应用了dapper,大家都晓得dapper是一个十分弱小的半自动化orm,帮程序员解决了繁琐的mapping问题,用起来十分爽,但我还是遇到了一件十分不爽的事件,如下代码所示: public class UserDAL : BaseDAL { public List<UserModel> GetList() { using (SqlConnection conn = new SqlConnection(ConnectionString)) { var list = conn.Query<UserModel>("select * from users").ToList(); return list; } } public bool Insert() { using (SqlConnection conn = new SqlConnection(ConnectionString)) { var execnum = conn.Execute("insert into xxx "); return execnum > 0; } } public bool Update() { using (SqlConnection conn = new SqlConnection(ConnectionString)) { var execnum = conn.Execute("update xxx ...."); return execnum > 0; } } } public class UserModel {}扫一下代码是不是总感觉哪里不对劲,是的,为了能应用上Dapper的扩大办法,这外面每个办法中都配上了模板化的 using (SqlConnection conn = new SqlConnection(ConnectionString)),尽管这样写逻辑上没有任何问题,但我有洁癖哈,接下来试着封装一下,嘿嘿,用更少的代码做更多的事件。 ...

August 5, 2020 · 2 min · jiezi

关于c#:api接口返回动态的json格式我太难了尝试一下-linq-to-json

一:背景1. 讲故事前段时间和一家公司联调api接口的时候,发现一个奇葩的问题,它的api返回的json会动静扭转,简化如下: {"Code":101,"Items":[{"OrderTitle":"订单1"}]}{"Code":102,"Items":[{"ProductTitle":"商品1"}]}逻辑是这样的: Items 中的内容会随的 Code 的扭转而扭转,外面有可能是订单列表又有可能是商品列表,习惯弱类型的敌人看这种json太失常不过了,但对于强类型的咱们来说,几乎就是一个大写的奇葩,你这让我用什么强类型反序列化呢???,如果还没了解,请看上面的这张图吧! 通过沟通,对方果然用的是弱类型的php,磨了半天,压服让对方改了返回构造,这样就能够间接用固有类匹配。 二:寻找解决办法从业务上来说,能压服对方退让那是最好的,但从技术上来说,这种场景有什么好的解决办法呢? 问题的实质就是json是动静的,你反序列化的时候无奈指定匹配类。 1. 应用 dynamic既然是动静的,那C#中也有一个动静类型 dynamic,何不用它来做json中动态变化的那局部的承受值,将 items 定义为 dynamic。如下图: 从图中看: rsp.Items as List<OrderItem> 返回是null,尝试失败,尽管转化失败了,但我置信你也看到了 Newtonsoft.Json.Linq.JArray,貌似这玩意能够用 linq 操控,对的, 这就是 linq to json。 2. 应用 linq to json有了linq根底,提取JArray中内容就不难了,接下来把代码改成如下: static void Main(string[] args) { var json = "{\"Code\":101,\"Items\":[{\"OrderTitle\":\"订单1\"}]}"; var rsp = JsonConvert.DeserializeObject<ApiResponse>(json); if (rsp.Code == 101) { var items = (rsp.Items as JArray).Select(m => m["OrderTitle"].Value<string>()).ToList(); Console.WriteLine(string.Join(",", items)); } if (rsp.Code == 102) { //todo .... } } ...

August 3, 2020 · 2 min · jiezi