首页 文章 精选 留言 我的

精选列表

搜索[c/c ],共10000篇文章
优秀的个人博客,低调大师

C#线程安全使用(五)

CancellationToken的多种应用 这是线程安全的最后一篇了,主要介绍CancellationToken的多种应用。 1,ThreadPool直接启动线程,传递CancellationToken。 2,Task启动线程,传递CancellationToken。Task传递方式分为两种,一种通过Task的参数进行传递,另一种通过向线程内传递对象的方式传递CancellationToken。 3,CancellationToken的回调函数应用。 话不多说,请看代码。 class Program { static void Main(string[] args) { Console.WriteLine("当前线程{0},当前状态{1}", Thread.CurrentThread.GetHashCode(), Thread.CurrentThread.ThreadState); //使用线程池创建线程,然后取消线程 CancelWithThreadPoolMiniSnippet(); } static CancellationTokenSource cts = new CancellationTokenSource(); static CancellationToken token = cts.Token; static void CancelWithThreadPoolMiniSnippet() { Console.WriteLine("当前线程{0},当前状态{1}", Thread.CurrentThread.GetHashCode(), Thread.CurrentThread.ThreadState); #region 使用QueueUserWorkItem的构造函数,传递cts.Token,但我不喜欢这个模式 跟踪不了状态 //ThreadPool.QueueUserWorkItem(new WaitCallback(DoSomeWork), ctn); #endregion #region 使用传递参数的模式 传递CancellationToken,这里的cts.Token是作为Action的参数传递的 //var action = new Action<object>(DoSomeWork); //Task t = new Task(action, ctn); //t.Start(); //Console.WriteLine("开始,当前线程{0},当前状态{1}", t.GetHashCode(), t.Status); #endregion #region 使用Task的构造函数,传递cts.Token,但CancellationTokenSource要弄成全局变量,否则方法找不到,就取消不了。 //Task t = new Task(Work, cts.Token); //t.Start(); #endregion #region 注册回调函数,当CancellationTokenSource.Cancel()执行后,调用回调函数 token.Register(CallBack, true); //注册回调函数 Task t = new Task(Work); t.Start(); #endregion Thread.SpinWait(5000000); cts.Cancel(); Console.WriteLine("结束,当前线程{0},当前状态{1}", t.GetHashCode(), t.Status); Console.Read(); } static void DoSomeWork(object obj) { CancellationToken token = (CancellationToken)obj; for (int i = 0; i < 100000; i++) { Console.WriteLine(i); // Simulating work. //Thread.SpinWait(5000000); if (token.IsCancellationRequested) { break; } } } static void Work() { for (int i = 0; i < 100000; i++) { Console.WriteLine(i); if (token.IsCancellationRequested) { break; } } } static void CallBack() { Console.WriteLine("I'm call back!" ); } } 代码内执行结果如下,该结果为CancellationToken的回调函数应用: 到此NET Framework4.0里的线程安全就都讲完了。。。。。。。 虽然第一篇文章是2013年,虽然历时近五年,但请相信我,代码早在五年前就已经写完啦。只是我一直一直一直没配文字发出来。。。。。。 不过,也可能是最近写文字的能力有所提升,所以就完成了四和五。 不然这线程安全的文章可能还要拖。。。。。。。。哈哈 后记 在NET Framework4.6里,微软提供了async和await语法,也是有关线程安全,我将会在新的语法相关文章里讲解async和await的用法。 ---------------------------------------------------------------------------------------------------- 注:此文章为原创,欢迎转载,请在文章页面明显位置给出此文链接!若您觉得这篇文章还不错请点击下右下角的推荐,非常感谢!

优秀的个人博客,低调大师

C# 登录界面 密码修改

form1: using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; namespace 简单登录界面 { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { String name = this.textBox1.Text; // 获取里面的值 String password = this.textBox2.Text; if (name.Equals("admin") && password.Equals("admin")) // 判断账号密码是否等于admin { MessageBox.Show("登录成功"); } else { MessageBox.Show("登录失败!"); } } private void button2_Click(object sender, EventArgs e) { Form2 form2 = new Form2(); form2.Show(); } } } form2: using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; namespace 简单登录界面 { public partial class Form2 : Form { public Form2() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { string userName = textBox1.Text; string oldPassWord = textBox2.Text; string newPassWord = textBox3.Text; string checkPassWord = textBox4.Text; if (oldPassWord != "admin") { MessageBox.Show("原密码错误!", "提示"); return; } if (newPassWord != checkPassWord) { MessageBox.Show("两次输入的密码不一致!", "提示"); return; } if (newPassWord.Length < 7) { MessageBox.Show("密码长度必须大于6个字符"); return; } if (newPassWord == oldPassWord) { MessageBox.Show("新旧密码不能一样"); return; } else { MessageBox.Show("密码修改成功"); } } private void button2_Click(object sender, EventArgs e) { Form2 form2 = new Form2(); form2.Close(); } } }

优秀的个人博客,低调大师

C++访问者模式

简述 访问者模式(Visitor Pattern)表示一个作用于某对象结构中的各元素的操作,它使你可以在不改变各元素类的前提下定义作用于这些元素的新操作。 简述 模式结构 优缺点 适用场景 案例分析 代码实现 版权所有:一去丶二三里,转载请注明出处:http://blog.csdn.net/liang19890820 模式结构 UML 结构图: Vistor(访问者):为对象结构中每一个 ConcreteElement 声明一个 visit() 操作,从这个操作的名称或参数类型可以清楚知道需要访问的具体元素的类型。 ConcreteVisitor(具体访问者):实现每个由 Visitor 声明的操作。 Element(元素):定义一个 accept() 操作,它通常以一个 Vistor 作为参数。 ConcreteElement(具体元素):实现 accept() 操作,通过调用 Visitor 的 visit() 方法来实现对元素的访问。 ObjectStructure(对象结构):能够枚举它的元素,同时提供一个高层的接口,以允许访问者访问它的元素。 优缺点 优点: 增加新的访问操作很方便。使用访问者模式,增加新的访问操作就意味着增加一个新的具体访问者类,实现简单,无须修改源代码,符合“开闭原则”。 将有关元素对象的访问行为集中到一个访问者对象中,而不是分散在一个个的元素类中。类的职责更加清晰,有利于对象结构中元素对象的复用,相同的对象结构可以供多个不同的访问者访问。 让用户能够在不修改现有元素类层次结构的情况下,定义作用于该层次结构的操作。 缺点: 增加新的元素类困难。每增加一个新的元素类都意味着要在访问者中增加一个新的操作,并在每一个具体访问者类中增加相应的具体操作,这违背了“开闭原则”的要求。 破坏封装。访问者模式要求访问者对象访问并调用每一个元素对象的操作,这意味着元素对象有时候必须暴露一些自己的内部操作和内部状态,否则无法供访问者访问。 适用场景 一个对象结构包含多个类型的对象,希望对这些对象实施一些依赖其具体类型的操作。在访问者中针对每一种具体的类型都提供了一个访问操作,不同类型的对象可以有不同的访问操作。 需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免让这些操作“污染”这些对象的类,也不希望在增加新操作时修改这些类。访问者模式使得我们可以将相关的访问操作集中起来定义在访问者类中,对象结构可以被多个不同的访问者类所使用,将对象本身与对象的访问操作分离。 对象结构中对象对应的类很少改变,但经常需要在此对象结构上定义新的操作。 案例分析 古城西安 - 访问记 西安历史悠久,有着 7000 多年文明史、3100 多年建城史、1100 多年的建都史,是中华文明和中华民族重要发祥地,丝绸之路的起点。。。西安与雅典、罗马、开罗并称为世界四大古都。 二十年中国看深圳,一百年中国看上海,一千年中国看北京,而五千年中国则看西安。 作为中国最佳的旅游胜地,西安有很多著名的景点:秦始皇兵马俑、大雁塔、大唐芙蓉园、华清池、钟/鼓楼、骊山、古城墙、历史博物馆。。。 在访问西安时,访问者会参观各个景点。对于景点来说,无论访问者是谁,它们都是不变的。而作为访问者,不同角色的访问方式也不尽相同,游客只负责旅游 - 吃喝玩乐,而清洁工则需要打扫卫生、清理垃圾。 这里,游客和清洁工是具体访问者,兵马俑、钟楼等景点是具体元素,西安这座城市是结构对象。 代码实现 创建访问者 访问者需要为每个景点都提供一个访问方法: // visitor.h #ifndef VISITOR_H #define VISITOR_H class BellTower; class TerracottaWarriors; // 访问者 class IVisitor { public: virtual ~IVisitor() {} virtual void Visit(BellTower *) = 0; virtual void Visit(TerracottaWarriors *) = 0; }; #endif // VISITOR_H 创建具体访问者 具体访问者有两种 - 游客、清洁工,它们分别实现了不同的访问操作(游客只管吃喝玩乐,清洁工负责清理垃圾): // concrete_visitor.h #ifndef CONCRETE_VISITOR_H #define CONCRETE_VISITOR_H #include "visitor.h" #include "concrete_element.h" // 游客 class Tourist : public IVisitor { public: virtual void Visit(BellTower *) override { std::cout << "I'm visiting the Bell Tower!" << std::endl; } virtual void Visit(TerracottaWarriors *) override { std::cout << "I'm visiting the Terracotta Warriors!" << std::endl; } }; // 清洁工 class Cleaner : public IVisitor { public: virtual void Visit(BellTower *) override { std::cout << "I'm cleaning up the garbage of Bell Tower!" << std::endl; } virtual void Visit(TerracottaWarriors *) override { std::cout << "I'm cleaning up the garbage of Terracotta Warriors!" << std::endl; } }; #endif // CONCRETE_VISITOR_H 创建元素 景点中定义了一个 Accept() 接口,用于接受访问者的访问: // element.h #ifndef ELEMENT_H #define ELEMENT_H class IVisitor; // 地方 class IPlace { public: virtual ~IPlace() {} virtual void Accept(IVisitor *visitor) = 0; }; #endif // ELEMENT_H 创建具体元素 具体元素有两个 - 钟楼、兵马俑,它们实现了 Accept() 方法: // concrete_element.h #ifndef CONCRETE_ELEMENT_H #define CONCRETE_ELEMENT_H #include "element.h" #include "visitor.h" #include <iostream> // 钟楼 class BellTower : public IPlace { public: virtual void Accept(IVisitor *visitor) override { std::cout << "Bell Tower is accepting visitor." << std::endl; visitor->Visit(this); } }; // 兵马俑 class TerracottaWarriors : public IPlace { public: virtual void Accept(IVisitor *visitor) override { std::cout << "Terracotta Warriors is accepting visitor." << std::endl; visitor->Visit(this); } }; #endif // CONCRETE_ELEMENT_H 注意: 在 Accept() 方法中,通过调用 Visitor 的 visit() 方法(以当前对象为参数)来实现对景点的访问。 创建对象结构 添加景点,并为每一个景点添加访问者: // object_structure.h #ifndef OBJECT_STRUCTURE_H #define OBJECT_STRUCTURE_H #include "element.h" #include <list> // 城市(西安) class City { public: void Attach(IPlace *place) { m_places.push_back(place); } void Detach(IPlace *place) { m_places.remove(place); } void Accept(IVisitor *visitor) { // 为每一个 element 设置 visitor,进行对应的操作 for (std::list<IPlace*>::iterator it = m_places.begin(); it != m_places.end(); ++it) { (*it)->Accept(visitor); } } private: std::list<IPlace *> m_places; }; #endif // OBJECT_STRUCTURE_H 创建客户端 欢迎来到古城西安,开始访问之旅吧: // main.cpp #include "concrete_visitor.h" #include "object_structure.h" #ifndef SAFE_DELETE #define SAFE_DELETE(p) { if(p){delete(p); (p)=NULL;} } #endif int main() { City *city = new City(); // 景点 - 钟楼、兵马俑 IPlace *bellTower = new BellTower(); IPlace *warriors = new TerracottaWarriors(); // 访问者 - 游客、清洁工 IVisitor *tourist = new Tourist(); IVisitor *cleaner = new Cleaner(); // 添加景点 city->Attach(bellTower); city->Attach(warriors); // 接受访问 city->Accept(tourist); city->Accept(cleaner); SAFE_DELETE(cleaner); SAFE_DELETE(tourist); SAFE_DELETE(warriors); SAFE_DELETE(bellTower); SAFE_DELETE(city); getchar(); return 0; } 输出如下: Bell Tower is accepting visitor. I’m visiting the Bell Tower! Terracotta Warriors is accepting visitor. I’m visiting the Terracotta Warriors! Bell Tower is accepting visitor. I’m cleaning up the garbage of Bell Tower! Terracotta Warriors is accepting visitor. I’m cleaning up the garbage of Terracotta Warriors!

优秀的个人博客,低调大师

C++备忘录模式

简述 备忘录模式(Memento Pattern)在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样可以在以后将对象恢复到原先保存的状态。 简述 模式结构 优缺点 适用场景 案例分析 代码实现 版权所有:一去丶二三里,转载请注明出处:http://blog.csdn.net/liang19890820 模式结构 UML 结构图: Originator(发起人):负责创建一个 Memento,以记录当前时刻自身的内部状态,并可以使用 Memento 恢复内部状态。Originator 可以根据需要决定 Memento 储存自己的哪些内部状态。 Memento(备忘录):负责存储 Originator 对象的内部状态,并可以防止 Originator 以外的其他对象访问备忘录。 Caretaker(管理者):负责管理 Memento,但不能对 Memento 的内容进行访问或者操作。 优缺点 优点: 提供了一种状态恢复机制,使用户能够方便地回到某个历史的状态。 实现了信息的封装,使得用户不需要关心状态的保存细节。 缺点: 如果 Originator 对象很大,那么 Memento 对象也会很大,这势必会占用较大的存储空间,而且每保存一次都需要消耗一定的系统资源。 适用场景 保存一个对象在某一个时刻的全部(或部分)状态,这样在以后需要时便能够恢复到先前的状态,实现撤销操作。 防止外界对象破坏一个对象历史状态的封装性,避免将对象历史状态的实现细节暴露给外界对象。 案例分析 月光宝盒 - 让时光倒流 很多人说年少时看《大话西游》,看着看着就笑了;长大之后再看,看着看着就哭了。无论是笑了还是哭了,心中总有很多疑惑无法解开。 《大话西游》依托于“月光宝盒”,构建了几个平行时空中发生的爱情故事。其中,有一个经典桥段: 至尊宝在盘丝洞找到盘丝大仙留下的月光宝盒,此时牛魔王带白晶晶来到盘丝洞。白晶晶以为春三十娘和二当家生下的孩子是她和至尊宝所生,愤而自刎。至尊宝为了救白晶晶,使用月光宝盒使时光倒流,几次后产生故障,竟将其带回五百年前,这时紫霞仙子向他走来 … 和“月光宝盒”一样,备忘录模式也提供了时光倒流的机制,将一个对象某个时刻的状态进行备份,当用户后悔(需要返回之前的状态)时,可以把备份调用出来! 代码实现 创建备忘录 穿越至某一时刻,这个时刻指具体的日期时间,用 DateTime 表示,并为其提供相应的 setter 和 getter 方法: // memento.h #ifndef MEMENTO_H #define MEMENTO_H #include <iostream> #include <string> // 日期时间 class DateTime { public: DateTime(std::string dt) : m_dateTime(dt) {} void SetDateTime(std::string dt) { m_dateTime = dt; } std::string GetDateTime() { return m_dateTime; } private: std::string m_dateTime; }; #endif // MEMENTO_H 创建发起人 Life 用于创建 DateTime,以记录当前的日期时间,并可以使用 DateTime 进行恢复: // originator.h #ifndef ORIGINATOR_H #define ORIGINATOR_H #include "memento.h" #include <iostream> #include <string> // 一生 class Life { public: void SetDateTime(std::string dt) { std::cout << "Set date time to " << dt << std::endl; m_dateTime = dt; } // 仅用于打印 std::string GetDateTime() { return m_dateTime; } // 恢复日期时间 void SetMemento(DateTime *dt) { m_dateTime = dt->GetDateTime(); } // 创建日期时间 DateTime *CreateMemento() { return new DateTime(m_dateTime); } private: std::string m_dateTime; }; #endif // ORIGINATOR_H 创建管理者 这是时光倒流的关键,通过 PandoraBox,至尊宝才可以弥补遗憾: // care_taker.h #ifndef CARE_TAKER_H #define CARE_TAKER_H #include "originator.h" #include <iostream> #include <vector> // 月光宝盒 class PandoraBox { public: PandoraBox(Life *life) : m_pLife(life) {} ~PandoraBox() { for (int i = 0; i < m_history.size(); i++) { delete m_history.at(i); } m_history.clear(); } // 保存备份 void Save() { std::cout << "Save ..." << std::endl;; m_history.push_back(m_pLife->CreateMemento()); } // 穿越至上一时刻 void Undo() { std::cout << "Undo ..." << std::endl;; m_pLife->SetMemento(m_history.back()); m_history.pop_back(); } private: Life *m_pLife; std::vector<DateTime *> m_history; }; #endif // CARE_TAKER_H 创建客户端 想启动“月光宝盒”,体验一把穿越的感觉?大声喊出那句烂熟于心的“般bō若rě波罗蜜”: // main.cpp #include "originator.h" #include "care_taker.h" #ifndef SAFE_DELETE #define SAFE_DELETE(p) { if(p){delete(p); (p)=NULL;} } #endif int main() { Life *life = new Life(); PandoraBox *box = new PandoraBox(life); // 设置并保存一个历史时间 life->SetDateTime("2000/10/01 00:00:00"); box->Save(); // 设置并保存一个历史时间 life->SetDateTime("2010/10/01 00:00:00"); box->Save(); // 设置一个历史时间 life->SetDateTime("2018/10/01 00:00:00"); // 穿越 box->Undo(); std::cout << "Actual date time is " << life->GetDateTime() << std::endl; // 再次穿越 box->Undo(); std::cout << "Actual date time is " << life->GetDateTime() << std::endl; SAFE_DELETE(life); SAFE_DELETE(box); getchar(); return 0; } 输出如下: Set date time to 2000/10/01 00:00:00 Save … Set date time to 2010/10/01 00:00:00 Save … Set date time to 2018/10/01 00:00:00 Undo … Actual date time is 2010/10/01 00:00:00 Undo … Actual date time is 2000/10/01 00:00:00

优秀的个人博客,低调大师

C# 中?和??的用法

最近在看官方的源码时,经常看到有 Int? sum; 和 FileProvider = FileProvider ??builder.GetFileProvider(); 一个问号: 很多数据类型时不允许为空的,比如int类型,在类型的后面加? 表示允许该数据为null 所以 Int? sum的含义时sum可以为int类型也可以为null 两个问号: 两个数据中间有两个问号,含义是 问号的左边的数据类型为空吗?如果为空,那么返回问号右边的数据,如果不为空,就返回问号左边的数据 所以 FileProvider = FileProvider ??builder.GetFileProvider(); 表示 FileProvider为空吗?如果为空,那么FileProvider=builder.GetFileProvider()否则FileProvider = FileProvider 意义和 FileProvider = FileProvider ==null?builder.GetFileProvider():FileProvider; 相同。

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册