C#订阅与发布标准实现 visual studio code .net 开发 设计模式之☞策略模式 C#字符串转二进制、二进制转字符串 c# 接口的协变和逆变 c# 使用迭代器来创建可枚举类型 博客园首页新随笔联系订阅管理 随笔 - 117 文章 - 0 评论 - 57 c# 创建,加载,修改XML文档
C#订阅与发布标准实现
大概看了下C#官方提供的IObservable接口以及IObserver接口来实现发布和订阅,写的很标准,很有代表性,做下笔记,以后要是项目需要用到发布订阅再基于自己的需求改:
public class BaggageInfo
{
private int flightNo;
private string origin;
private int location;
internal BaggageInfo(int flight, string from, int carousel)
{
this.flightNo = flight;
this.origin = from;
this.location = carousel;
}
public int FlightNumber {
get { return this.flightNo; }
}
public string From {
get { return this.origin; }
}
public int Carousel {
get { return this.location; }
}
}
///
/// 发布者
///
public class BaggageHandler : IObservable<BaggageInfo>
{
private List<IObserver<BaggageInfo>> observers;
private List<BaggageInfo> flights;
public BaggageHandler()
{
observers = new List<IObserver<BaggageInfo>>();
flights = new List<BaggageInfo>();
}
public IDisposable Subscribe(IObserver<BaggageInfo> observer)
{
// Check whether observer is already registered. If not, add it
if (! observers.Contains(observer)) {
observers.Add(observer);
// Provide observer with existing data.
foreach (var item in flights)
observer.OnNext(item);
}
return new Unsubscriber<BaggageInfo>(observers, observer);
}
// Called to indicate all baggage is now unloaded.
public void BaggageStatus(int flightNo)
{
BaggageStatus(flightNo, String.Empty, 0);
}
public void BaggageStatus(int flightNo, string from, int carousel)
{
var info = new BaggageInfo(flightNo, from, carousel);
// Carousel is assigned, so add new info object to list.
if (carousel > 0 && ! flights.Contains(info)) {
flights.Add(info);
foreach (var observer in observers)
observer.OnNext(info);
}
else if (carousel == 0) {
// Baggage claim for flight is done
var flightsToRemove = new List<BaggageInfo>();
foreach (var flight in flights) {
if (info.FlightNumber == flight.FlightNumber) {
flightsToRemove.Add(flight);
foreach (var observer in observers)
observer.OnNext(info);
}
}
foreach (var flightToRemove in flightsToRemove)
flights.Remove(flightToRemove);
flightsToRemove.Clear();
}
}
public void LastBaggageClaimed()
{
foreach (var observer in observers)
observer.OnCompleted();
observers.Clear();
}
}
internal class Unsubscriber<BaggageInfo> : IDisposable
{
private List<IObserver<BaggageInfo>> _observers;
private IObserver<BaggageInfo> _observer;
internal Unsubscriber(List<IObserver<BaggageInfo>> observers, IObserver<BaggageInfo> observer)
{
this._observers = observers;
this._observer = observer;
}
public void Dispose()
{
if (_observers.Contains(_observer))
_observers.Remove(_observer);
}
}
///
/// 订阅者
///
public class ArrivalsMonitor : IObserver<BaggageInfo>
{
private string name;
private List<string> flightInfos = new List<string>();
private IDisposable cancellation;
private string fmt = "{0,-20} {1,5} {2, 3}";
public ArrivalsMonitor(string name)
{
if (String.IsNullOrEmpty(name))
throw new ArgumentNullException("The observer must be assigned a name.");
this.name = name;
}
public virtual void Subscribe(BaggageHandler provider)
{
cancellation = provider.Subscribe(this);
}
public virtual void Unsubscribe()
{
cancellation.Dispose();
flightInfos.Clear();
}
public virtual void OnCompleted()
{
flightInfos.Clear();
}
// No implementation needed: Method is not called by the BaggageHandler class.
public virtual void OnError(Exception e)
{
// No implementation.
}
// Update information.
public virtual void OnNext(BaggageInfo info)
{
bool updated = false;
// Flight has unloaded its baggage; remove from the monitor.
if (info.Carousel == 0) {
var flightsToRemove = new List<string>();
string flightNo = String.Format("{0,5}", info.FlightNumber);
foreach (var flightInfo in flightInfos) {
if (flightInfo.Substring(21, 5).Equals(flightNo)) {
flightsToRemove.Add(flightInfo);
updated = true;
}
}
foreach (var flightToRemove in flightsToRemove)
flightInfos.Remove(flightToRemove);
flightsToRemove.Clear();
}
else {
// Add flight if it does not exist in the collection.
string flightInfo = String.Format(fmt, info.From, info.FlightNumber, info.Carousel);
if (! flightInfos.Contains(flightInfo)) {
flightInfos.Add(flightInfo);
updated = true;
}
}
if (updated) {
flightInfos.Sort();
Console.WriteLine("Arrivals information from {0}", this.name);
foreach (var flightInfo in flightInfos)
Console.WriteLine(flightInfo);
Console.WriteLine();
}
}
}
using System;
using System.Collections.Generic;
public class Example
{
public static void Main()
{
//发布者
BaggageHandler provider = new BaggageHandler();
// 订阅者
ArrivalsMonitor observer1 = new ArrivalsMonitor("BaggageClaimMonitor1");
// 订阅者
ArrivalsMonitor observer2 = new ArrivalsMonitor("SecurityExit");
// 发布
provider.BaggageStatus(712, "Detroit", 3);
//订阅
observer1.Subscribe(provider);
provider.BaggageStatus(712, "Kalamazoo", 3);
provider.BaggageStatus(400, "New York-Kennedy", 1);
provider.BaggageStatus(712, "Detroit", 3);
observer2.Subscribe(provider);
provider.BaggageStatus(511, "San Francisco", 2);
provider.BaggageStatus(712);
observer2.Unsubscribe();
provider.BaggageStatus(400);
provider.LastBaggageClaimed();
}
}
visual studio code .net 开发
Visual Studio确实是相当好用,各种简化操作什么的简直不要太舒服。但其容量太大,有时不是很方便,所以今天简单介绍一下另一个工具--Visual Studio Code.
虽然相比于老大哥Visual Studio,VS Code有很多功能不完善,但它也更灵活轻便。并且VS Code还在不断的更新当中,目前的最新版本是18年11月更新的1.30版本,包含了 多行搜索改进 等内容。
下面以.Net开发为例:
不同于Visual Studio,在VS Code上进行.Net开发你需要安装一些插件,点击左侧边栏箭头这个位置搜索

安装插件 C# (C# for Visual Studio Code (powered by OmniSharp)) (必须)
- Lightweight development tools for .NET Core.
- Great C# editing support, including Syntax Highlighting, IntelliSense, Go to Definition, Find
- All References, etc.
- Debugging support for .NET Core (CoreCLR). NOTE: Mono debugging is not supported. Desktop CLR debugging has limited support.
- Support for project.json and csproj projects on Windows, macOS and Linux.
安装插件 NuGet Package Manager (推荐,方便搜索,安装Nuget包) (推荐)
- Search the NuGet package repository for packages using either (partial or full) package name or another search term.
- Add PackageReference dependencies to your .NET Core 1.1+ .csproj or .fsproj files from Visual Studio Code's Command Palette.
- Remove installed packages from your project's .csproj or .fsproj files via Visual Studio Code's Command Palette.
- Handles workspaces with multiple .csproj or .fsproj files as well as workspaces with single .csproj/.fsproj files.
- For example:
- Ctrl + P Then Shift + > Choose "Nuget Package Manager: Add Package". Then Input the keyword about the Nuget Package. Finally, Choose the project you want to add the Nuget package.
VSCode 安装插件后一般需要重新激活以启用插件。由于VSCode本身不断更新,对于某些版本的VSCode可能需要重启应用,才能激活插件。
在VSCode中运行调试前,需要在.vscode路径下额外配置两个文件 launch.json 和 tasks.json, 来告诉vscode如何启动项目。
Launch.json:
{
// Use IntelliSense to find out which attributes exist for C# debugging
// Use hover for the description of the existing attributes
// For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md
"version": "0.2.0",
"configurations": [
{
"name": ".NET Core Launch (web)",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build",
// If you have changed target frameworks, make sure to update the program path.
"program": "${workspaceRoot}/MyABP.Web/bin/Debug/netcoreapp2.1/MyABP.Web.dll",
"args": [],
"cwd": "${workspaceRoot}/MyABP.Web",
"stopAtEntry": false,
"internalConsoleOptions": "openOnSessionStart",
"launchBrowser": {
"enabled": true,
"args": "${auto-detect-url}",
"windows": {
"command": "cmd.exe",
"args": "/C start ${auto-detect-url}"
},
"osx": {
"command": "open"
},
"linux": {
"command": "xdg-open"
}
},
"env": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"sourceFileMap": {
"/Views": "${workspaceRoot}/Views"
}
},
{
"name": ".NET Core Attach",
"type": "coreclr",
"request": "attach",
"processId": "${command:pickProcess}"
}
]
}
如果你第一次运行某个项目,你需要确保所有引用的内容都存在,如上面的MyAbp.Web.dll文件.另外,这些配置不是固定不变的,你可以根据你的需要来进行不同的配置。
如上面
"preLaunchTask": "build" 指定了你的项目在launch之前要先进行build操作。
又如
"env": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
指定了你要在“哪个环境”下启动你的项目。(实际上一个项目会有多种环境的配置,举个例子 appsetings.Development.json 和 appseting.QA.json用于区分不同环境的配置,如果发现在QA环境出现了问题本地不能重现时,自然需要切换到目标环境来进行调试)
Tasks.json:
{
"version": "0.1.0",
"command": "dotnet",
"isShellCommand": true,
"args": [],
"tasks": [
{
"taskName": "build",
"args": [
"${workspaceRoot}/MyABP.Web/MyABP.Web.csproj"
],
"isBuildCommand": true,
"problemMatcher": "$msCompile"
}
]
}
这里可以配置一下Task,如上面的
"preLaunchTask": "build" 具体的任务流程即在这里配置。
这里除去笔者使用的Web项目的配置外,当然还可以有多种其他项目应用的配置,如

这些配置完成之后,点击如图所示这个位置进入调试面板,然后点击上面的绿色三角就可以开始你的调试啦

/ **************************************************分割线*************************************************************/
vscode下常用DotNet命令
dotnet所使用的命令都可以使用 --help的方式来查看更详细的用法。
如dotnet --help
在项目开发过程中,常用的命令有
dotnet new
用于新建内容,dotnet提供了许多模板,如Console Application, Class Library等等。
使用dotnet new时需要注意新建的项目是基于.Net Framework还是基于.NetCore.
可以使用 -f 来指定.
dotnet restore
主要是寻找当前目录下的项目文件(project.json),然后利用NuGet库还原整个项目的依赖库,然后遍历每个目录,生成项目文件,继续还原该项目文件中的依赖项 --CSDN yangzhenping
以下命令不解释了,可以使用 --help 查看具体用法
dotnet build
dotnet run
dotnet publish
设计模式之☞策略模式
策略模式:它定义了算法家族,分别封装起来,让它们之间可以相互替换,此模式让算法的变化,不会影响到使用算法的客户。
今天来通过一个案例,来讲一下商场的促销案例。一般商场会有那些活动呢?总结了下,一般会有这3种促销活动:1、正常收费;2、打折;3、满多少返多少
面向对象的编程,并不是类越多越好,类的划分是为了封装,但分类的基础是抽象,具有相同属性和功能的抽象集合才是类。
现金收费抽象类:
1 abstract class CashSupper //现金收费抽象类
2 {
3 public abstract double acceptCash(double money);//现金收取类的抽象方法,收取现金,参数为原价,返回为当前价
4 }
正常收费子类:
1 class CashNormal : CashSupper //正常收费子类
2 {
3 public override double acceptCash(double money)
4 {
5 return money;
6 }
7 }
打折收费子类:
1 class CashRebate : CashSupper //打折收费子类
2 {
3 private double moneryRebate = 1d;
4 public CashRebate(string moneryRebate)
5 {
6 this.moneryRebate = double.Parse(moneryRebate); //打折收费,初始化时,必须要输入折扣率,如八折,就是0.8
7 }
8 public override double acceptCash(double money)
9 {
10 return money * moneryRebate;
11 }
12 }
返利收费子类:
1 class CashReturn : CashSupper
2 {
3 private double moneryCondition = 0.0d;
4 private double MoneryReturn = 0.0d;
5 public CashReturn(string moneryCondition,string moneryReturn) //返利收费,初始化时必须要输入返利条件和返利值,比如满300返100,则moneryCondition=300,moneryReturn=100
6 {
7 this.moneryCondition =double.Parse(moneryCondition);
8 this.MoneryReturn = double.Parse(moneryReturn);
9 }
10 public override double acceptCash(double money)
11 {
12 double result = money;
13 if (money>=moneryCondition) //若大于返利条件,则需要减去返利值
14 {
15 result = money - Math.Floor(money / moneryCondition) * MoneryReturn;
16 }
17 return result;
18 }
19 }
现金收费工厂类:
1 class CashFactory
2 {
3 public static CashSupper createCashAccept(string type)
4 {
5 CashSupper cs = null;
6 switch (type)
7 {
8 case "正常收费":
9 cs = new CashNormal();
10 break;
11 case "满300反100":
12 CashReturn cr1 = new CashReturn("300","100");
13 cs = cr1;
14 break;
15 case "打8折":
16 CashRebate cr2 = new CashRebate("0.8");
17 cs = cr2;
18 break;
19 }
20 return cs;
21 }
22 }
CashContext类:
1 class CashContext
2 {
3 private CashSupper cs=null; //声明一个CashSuper
4 public CashContext(string type) //表示收费的类型
5 {
6 switch (type)
7 {
8 case "正常收费":
9 CashNormal cs0 = new CashNormal();
10 cs = cs0;
11 break;
12 case "满300返100":
13 CashReturn cr1 = new CashReturn("300","100");
14 cs = cr1;
15 break;
16 case "打8折":
17 CashRebate cr2 = new CashRebate("0.8"); //将实例化具体策略的过程由客户端转移到Context类中。简单工厂的引用
18 cs = cr2;
19 break;
20 }
21 }
22 public double GetResult(double Money)
23 {
24 return cs.acceptCash(Money); //根据收费策略的不同,获得计算结果
25 }
26 }
界面:

调用:
1 double total = 0.0d; //用户总计
2 private void btnOk_Click(object sender, EventArgs e)
3 {
4 CashContext cc = new CashContext(cmbType.SelectedItem.ToString());
5 double totalPrices = 0d;
6 totalPrices = cc.GetResult(Convert.ToDouble(txtPrice.Text)*Convert.ToDouble(txtNumber.Text)); //通过对Context的GetResult方法的调用,可以得到收取费用的结果,让具体算法与客户进行隔离
7 total = total + totalPrices;
8 listBox1.Items.Add("单价:"+txtPrice.Text+"数量:"+txtNumber.Text+" "+cmbType.SelectedItem+"合计:"+totalPrices.ToString());
9 label5.Text = total.ToString();
10 }
C#字符串转二进制、二进制转字符串
最近公司要做一个操作日志的模块,如果将操作日志以字符串的形式存到后台数据库,非常浪费内存,不可取,特意写了字符串与二进制相互转换的函数。
1、字符串转二进制
1 private string StringToBinary(string str)
2 {
3 byte[] data = Encoding.Unicode.GetBytes(str);
4 StringBuilder sb = new StringBuilder(data.Length*8);
5 foreach (byte item in data)
6 {
7 sb.Append(Convert.ToString(item,2).PadLeft(8,'0'));
8 }
9 return sb.ToString();
10 }
2、二进制转字符串
1 private string BinaryToString(string str)
2 {
3 System.Text.RegularExpressions.CaptureCollection cs = System.Text.RegularExpressions.Regex.Match(str,@"([01]{8})+").Groups[1].Captures;
4 byte[] data = new byte[cs.Count];
5 for (int i = 0; i < cs.Count; i++)
6 {
7 data[i] = Convert.ToByte(cs[i].Value,2);
8 }
9 return Encoding.Unicode.GetString(data,0,data.Length);
10 }
下面随便写了一条Sql语句,便于测试两者是否转换成功?


转码成功!
c# 接口的协变和逆变
如果派生类只是用于输出值,那么这种结构化的委托有效性之间的常数关系叫做协变
就是创建一个派生类委托对象 让派生类赋值给基类对象 协变关键字out
对期望传入基类时允许传入派生对象的特性叫逆变 逆变关键字in
看一下实现代码
class Animal { public string Name; }
class Dog:Animal { }
interface Im<out T>//协变
{
T GetT();
}
class MyClass<T> : Im<T>
{
public T[] item = new T[2];
public T GetT()
{
return item[0];
}
}
class Program
{
static void DoSomething(Im<Animal> im)
{
Console.WriteLine(im.GetT().Name);
}
static void Main(string[] args)
{
MyClass<Dog> myClass = new MyClass<Dog>();
myClass.item[0] = new Dog() { Name = "AVT" };
Im<Animal> ANIMAL = myClass;
DoSomething(myClass);
}
}
c# 使用迭代器来创建可枚举类型
class Program
{
public IEnumerator<string> GetEnumerator()
{
IEnumerable<string> my = BlackAndWhite();
return my.GetEnumerator();
}
public IEnumerable<string> BlackAndWhite()
{
yield return "black";
yield return "gray";
yield return "white";
}
static void Main(string[] args)
{
Program program = new Program();
foreach (var item in program)
{
Console.WriteLine(item);
}
foreach (var item in program.BlackAndWhite())
{
Console.WriteLine(item);
}
}
}
c# 创建,加载,修改XML文档
using System.Xml.Linq;
static void Main(string[] args) { XDocument xDocument = new XDocument(new XElement("mployess", //创建跟元素 new XElement("name", "a"),new XElement("name","b")));//创建元素 xDocument.Save("地址"); XDocument empole = XDocument.Load("地址");//加载xml 文档 可以保证修改 Console.WriteLine(empole); }


浙公网安备 33010602011771号