ps:废话不多说。直接上代码:源码地址:https://github.com/786744873/Asp.Net-Core-2.1-All-Demos/tree/master/src
Configuration的配置
说明:基于三种方式的读取配置文件以及自定义读取自定义配置文件
文件结构
代码
PropertiesConfigurationProvider.cs
public class PropertiesConfigurationProvider:ConfigurationProvider { string _path = string.Empty; public PropertiesConfigurationProvider(string path) { this._path = path; } /// <summary> /// 用于解析1.properties /// </summary> public override void Load() { var lines = File.ReadAllLines(this._path); var dict = new Dictionary<string, string>(); foreach (var line in lines) { var items = line.Split('='); dict.Add(items[0], items[1]); } this.Data = dict; } }
PropertiesConfigurationSource.cs
public class PropertiesConfigurationSource : IConfigurationSource { string _path = string.Empty; public PropertiesConfigurationSource(string path) { this._path = path; } public IConfigurationProvider Build(IConfigurationBuilder builder) { return new PropertiesConfigurationProvider(_path); } }
PropertiesConfigurationExtensions.cs
public static class PropertiesConfigurationExtensions { public static IConfigurationBuilder AddPropertiesFile(this IConfigurationBuilder builder, string path) { builder.Add(new PropertiesConfigurationSource(path)); return builder; } }
1.properties
port=8080 host=127.0.0.1
appsettings.json
{ "mysql": { "host": "127.0.0.1", "port": 3306 }, "shopidlist": [ { "entid": 20 }, { "entid": 25 } ] }
Program.cs
class Program { static void Main(string[] args) { IConfiguration Configuration = new ConfigurationBuilder() .SetBasePath(Environment.CurrentDirectory) .AddJsonFile("appsettings.json", optional:true,reloadOnChange:true) .AddPropertiesFile("1.properties")//加载自定义文件 .Build(); Appsettings appsettings = new Appsettings(); Configuration.Bind(appsettings); Console.WriteLine(appsettings.mysql.port); Console.WriteLine(Configuration["mysql:port"]); Console.WriteLine(Configuration.GetValue<int>("mysql:port")); Console.WriteLine(Configuration.GetSection("mysql").GetSection("port").Value); //读取自定义文件 Console.WriteLine(Configuration["host"]); Console.Read(); } } public class Appsettings { public Mysql mysql { get; set; } public Shopidlist[] shopidlist { get; set; } } public class Mysql { public string host { get; set; } public int port { get; set; } } public class Shopidlist { public int entid { get; set; } }
CollectionService注入
文件结构
代码
Program.cs
class Program { static void Main(string[] args) { //IOC容器 ServiceCollection services = new ServiceCollection(); //注册服务 services.AddScoped<IFlay, Pig>(); //注册日志服务 services.AddLogging(); var provider = services.BuildServiceProvider(); provider.GetService<ILoggerFactory>().AddConsole(LogLevel.Debug); var fly = provider.GetService<IFlay>(); fly.Flay(); } } public interface IFlay { void Flay(); } public class Pig : IFlay { ILogger<Pig> logger = null; public Pig(ILoggerFactory loggerFactory) { logger=loggerFactory.CreateLogger<Pig>(); } public void Flay() { logger.LogInformation("这是Console日志"); Console.WriteLine("风口来了,猪都会飞了!"); } }
AOP AspectCore
文件结构
代码
Program.cs
//https://github.com/dotnetcore/AspectCore-Framework class Program { static void Main(string[] args) { ServiceCollection services = new ServiceCollection(); //注册AspectCore动态代理服务 services.AddDynamicProxy(); services.AddTransient<IMySql, MySql>(); var provider= services.BuildDynamicProxyServiceProvider(); var mysql = provider.GetService<IMySql>(); //走业务逻辑 var msg= mysql.GetData(10); Console.WriteLine(msg); //走缓存 msg = mysql.GetData(10); Console.WriteLine(msg); } } public class MysqlInterceptorAttribute : AbstractInterceptorAttribute { private Dictionary<string, string> cacheDict = new Dictionary<string, string>(); public override Task Invoke(AspectContext context, AspectDelegate next) { //用id作为cachekey var cacheKey = string.Join(",", context.Parameters); if (cacheDict.ContainsKey(cacheKey)) { context.ReturnValue = cacheDict[cacheKey]; return Task.CompletedTask; } var task = next(context); //ReturnValue实际上就是一个传递值的媒介 var cacheValue = context.ReturnValue; cacheDict.Add(cacheKey, $"from Cache:{cacheValue.ToString()}"); return task; //Console.WriteLine("开始记录日志。。。。"); //var task = next(context); //Console.WriteLine("结束记录日志。。。。"); //return task; } } public interface IMySql { [MysqlInterceptor] string GetData(int id); } public class MySql : IMySql { public string GetData(int id) { var msg = $"已经获取到id={id}的数据"; //Console.WriteLine(msg); return msg; } }
MemoryCache
文件结构
代码
Program.cs
class Program { static void Main(string[] args) { {//cache的最大限度为100 MemoryCache memoryCache = new MemoryCache(new MemoryCacheOptions() { SizeLimit = 100 }); for (int i = 0; i < 1000; i++) { memoryCache.Set<string>(i.ToString(), i.ToString(), new MemoryCacheEntryOptions() { Size = 1 }); Console.WriteLine(memoryCache.Count); } } {//被动过期,设置过期回调 MemoryCache memoryCache = new MemoryCache(new MemoryCacheOptions() { }); var cacheOptions = new MemoryCacheEntryOptions { AbsoluteExpiration = DateTimeOffset.Now.AddSeconds(3),//3秒过期 }; cacheOptions.RegisterPostEvictionCallback((key, value, reason, obj) => { Console.WriteLine(reason); Console.WriteLine("执行过期回调"); }); memoryCache.Set("key", "value", cacheOptions); Console.WriteLine("3秒后过期将执行回调"); while (true) { Thread.Sleep(1000); Console.WriteLine(memoryCache.Get<string>("key")); } Console.ReadKey(); } {//主动过期(10秒被动过期,2秒主动使用token让他过期) CancellationTokenSource tokenSource = new CancellationTokenSource(); MemoryCache memoryCache = new MemoryCache(new MemoryCacheOptions() { }); var cacheOptions = new MemoryCacheEntryOptions { AbsoluteExpiration = DateTimeOffset.Now.AddSeconds(10),//10秒过期 }; cacheOptions.AddExpirationToken(new CancellationChangeToken(tokenSource.Token));//加入Token cacheOptions.RegisterPostEvictionCallback((key, value, reason, obj) => { Console.WriteLine(reason); Console.WriteLine("执行过期回调"); }); memoryCache.Set("key", "value", cacheOptions); Console.WriteLine("10秒后过期将执行回调"); tokenSource.CancelAfter(TimeSpan.FromSeconds(2)); while (true) { Thread.Sleep(1000); Console.WriteLine(memoryCache.Get<string>("key")); } Console.ReadKey(); } } }
Redis MongoDB
文件结构
代码
Program.cs
class Program { static void Main(string[] args) { //Redis { RedisCache redisCache = new RedisCache(new RedisCacheOptions() { Configuration = "127.0.0.1:6379", InstanceName = "test" }); //在Redis中是以Hash的模式存放的 redisCache.SetString("username", "jack", new DistributedCacheEntryOptions { AbsoluteExpiration = DateTime.Now.AddDays(1), }); var info = redisCache.GetString("username"); Console.WriteLine(info); } //MongoDB { MongoDBCache mongoDBCache = new MongoDBCache(new MongoDBCacheOptions() { ConnectionString = "mongodb://127.0.0.1:27017", DatabaseName = "mydb", CollectionName = "mytest" }); mongoDBCache.Set("username", Encoding.UTF8.GetBytes("jack"), new DistributedCacheEntryOptions { AbsoluteExpiration = DateTime.Now.AddDays(1) }); var info= Encoding.UTF8.GetString(mongoDBCache.Get("username")); Console.WriteLine(info); } } }
Mysql.Data Dapper
文件结构
代码
class Program { static void Main(string[] args) { //MySql.Data { var connectString = "server=127.0.0.1;por=3306;userid=root;pwd=123456;database=datamip;SslMode=none;"; //MySqlConnection mySqlConnection = new MySqlConnection(connectString); //select var ds = MySqlHelper.ExecuteDataset(connectString, "select * from users"); //select2 var reader = MySqlHelper.ExecuteReader(connectString, "select * from users"); var user = new Users(); while (reader.Read()) { user.UserId = reader.GetInt32("UserID"); user.UserNick = reader.GetString("UserNick"); user.LoginIP = reader.GetString("LoginIP"); user.Email = reader.GetString("Email"); } reader.Close(); //update var result = MySqlHelper.ExecuteNonQuery(connectString, "update users set Email='786744873@qq.com' where UserID=1"); } //Dapper { var connectString = "server=127.0.0.1;por=3306;userid=root;pwd=123456;database=datamip;SslMode=none;"; MySqlConnection mySqlConnection = new MySqlConnection(connectString); //select var userList = mySqlConnection.Query<Users>("select * from users where UserID=@UserID",new { UserID=2 }); //update var nums = mySqlConnection.Execute("update users set Email='786744873@qq.com' where UserID=1"); } } class Users { public int UserId { get; set; } public string UserNick { get; set; } public string LoginIP { get; set; } public string Email { get; set; } } }
nohup supervisord部署Unbuntu
不得不说Ubuntu18.04版本是个巨坑。还是老老实实用16.04吧,错了,是VirtualBox是个巨坑,这wtf软件各种问题,浪费我几天时间,艹
文件结构
代码
ConfigurationManager.cs
public class ConfigurationManager { public static IConfigurationRoot Configuration { get { var configuration = new ConfigurationBuilder() .SetBasePath(Directory.GetCurrentDirectory()) .AddJsonFile(string.Format("appsettings.{0}.json", Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")),optional:true,reloadOnChange:true) .AddJsonFile(string.Format("ops.{0}.json", Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")),optional:true,reloadOnChange:true) .Build(); return configuration; } } }
Program.cs
class Program { static void Main(string[] args) { var tokenSource = new CancellationTokenSource(); Task.Factory.StartNew(() => { while (!tokenSource.IsCancellationRequested) { Console.WriteLine($"{DateTime.Now}:业务逻辑处理中"); Thread.Sleep(1000); } }).ContinueWith(t => { Console.WriteLine("服务安全退出!"); Environment.Exit(0);//强制退出 }); Console.WriteLine("服务成功开启"); while (!"Y".Equals(ConfigurationManager.Configuration["isquit"],StringComparison.InvariantCultureIgnoreCase)) { Thread.Sleep(1000); } tokenSource.Cancel(); } }
ops.Development.json || ops.Production.json
{ "isquit": "N" }
部署过程
直接发布,发布以及虚拟机安装参照之前的博客:Virtual Box虚拟机Ubuntu18.X系统安装及Mysql基本开发配置,这里主要讲如何进行持久化
ubuntu16.04开机提示:检测到系统程序出现问题
打开终端,输入 sudo gedit /etc/default/apport 把enabled=1改成enabled=0
方案一:nohub部署
先执行 nohup dotnet 程序集名称 &
nohup dotnet ConsoleApp7.dll & #(符号&使程序在后台运行)
exit #(退出nohup模式)
然后输入 exit 进行退出,不然的话后台进程会被终结
启动后,会将程序运行输出记录在当前目录下的nohup.out文件下,如果当前目录不可写,则会被记录在Home目录下的nohup.out文件中
nohup dotnet ConsoleApp7.dll > my_nohup.log 2>&1 & #(将日志输出在my_nohup.log文件中,并将stderr重定向至stdout)
查看dotnet进程
ps -ef |grep dotnet
查看后10行nohup输出
tail /home/wyt/nohup.out
查看运行的后台进程
ps -ef | grep dotnet
停止程序
kill -9 12462 #(根据进程号关闭程序)
方案二:supervisord部署
安装
ubuntu安装: sudo apt-get install supervisor centos安装: yum install -y supervisor
安装成功后,会在 /etc/supervisor 目录下,生成 supervisord.conf 配置文件。
你也可以使用 echo_supervisord_conf > supervisord.conf 命令,生成默认的配置文件(不建议,内容比较多)。
supervisord.conf 示例配置:
; supervisor config file [unix_http_server] file=/var/run/supervisor.sock ; (the path to the socket file) chmod=0700 ; sockef file mode (default 0700) [supervisord] logfile=/var/log/supervisor/supervisord.log ; (main log file;default $CWD/supervisord.log) pidfile=/var/run/supervisord.pid ; (supervisord pidfile;default supervisord.pid) childlogdir=/var/log/supervisor ; ('AUTO' child log dir, default $TEMP) ; the below section must remain in the config file for RPC ; (supervisorctl/web interface) to work, additional interfaces may be ; added by defining them in separate rpcinterface: sections [rpcinterface:supervisor] supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface [supervisorctl] serverurl=unix:///var/run/supervisor.sock ; use a unix:// URL for a unix socket ; The [include] section can just contain the "files" setting. This ; setting can list multiple files (separated by whitespace or ; newlines). It can also contain wildcards. The filenames are ; interpreted as relative to this file. Included files *cannot* ; include files themselves. [include] files = /etc/supervisor/conf.d/*.conf
进程配置会读取 /etc/supervisor/conf.d 目录下的 *.conf 配置文件,我们在此目录下创建一个 ConsoleApp7.conf 进程配置文件:
[program:ConsoleApp7] directory=/data/output command=/usr/bin/dotnet /data/output/ConsoleApp7.dll autostart=true autorestart=true startretries=10 redirect_stderr=true stdout_logfile=/data/output/logs/out.log stderr_logfile=/data/output/logs/out.log environment=ASPNETCORE_ENVIRONMENT="Development"
需要注意的是,如果不是 root 账号,需要对这些目录进行权限设置,要不然会报一些错误(一定要在 root 账号下进行配置,要不然一系列权限引起的问题?)。
sudo chmod 777 /var/run sudo chmod 777 /etc/supervisor
接着就可以启动 Supervisord 了:
sudo supervisorctl reload
sudo supervisord
sudo supervisorctl ConsoleApp7
supervisorctl 常用命令:
命令 | 说明 |
---|---|
sudo supervisorctl stop program_name | 停止某个进程 |
sudo supervisorctl start program_name | 启动某个进程 |
sudo supervisorctl restart program_name | 重启某个进程 |
sudo supervisorctl stop all | 停止全部进程 |
sudo supervisorctl reload | 载入最新的配置文件,停止原有进程并按新的配置启动、管理所有进程 |
sudo supervisorctl update | 根据最新的配置文件,启动新配置或有改动的进程,配置没有改动的进程不会受影响而重启 |
运行成功后查看守护进程信息
sudo supervisorctl status all
使用NSSM进行Windows部署
NSSM是一款可将Nodejs项目注册为Windows系统服务的工具。当你的Node.js项目需要部署在Windows Server上时,NSSM是一个不错的选择。
使用
- 下载NSSM download.
- 根据自己的平台,将32/64位nssm.exe文件解压至任意文件夹。
- cmd定位至nssm.exe所在目录。
- 输入
nssm install {服务名称}
,即注册服务的名称。注册服务弹出如下NSSM界面。
Socket实现简单Web服务器
文件结构
代码
WebServer.cs
1 public class WebServer 2 { 3 static Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 4 5 public static void Start() 6 { 7 socket.Bind(new IPEndPoint(IPAddress.Any, 8200)); 8 socket.Listen(100); 9 10 //接收客户端的Socket请求 11 socket.BeginAccept(OnAccept, socket); 12 13 Console.WriteLine("当前Web服务器启动成功,端口号为8200"); 14 } 15 16 //接收请求 17 public static void OnAccept(IAsyncResult async) 18 { 19 var serverSocket = async.AsyncState as Socket; 20 21 //获取到客户端的Socket 22 var clientSocket = serverSocket.EndAccept(async); 23 24 //进行下一步监听 25 serverSocket.BeginAccept(OnAccept, socket); 26 27 //获取其内容 28 var bytes = new byte[10240]; 29 var len = clientSocket.Receive(bytes); 30 var request = Encoding.UTF8.GetString(bytes, 0, len); 31 32 var response = string.Empty; 33 34 if (!string.IsNullOrEmpty(request)&&!request.Contains("favicon.ico")) 35 { 36 //1.html 37 var filePath = request.Split("\r\n")[0].Split(" ")[1].Replace("/", ""); 38 39 //获取文件内容 40 response = File.ReadAllText(filePath, Encoding.UTF8); 41 } 42 43 //按照Http响应码返回 44 var responseHeader = string.Format(@"HTTP/1.1 200 OK 45 Date: Tue, 11 Dec 2018 07:08:44 GMT 46 Content-Type: text/html; charset=utf-8 47 Content-Length: {0} 48 Connection: keep-alive 49 Vary: Accept-Encoding 50 Cache-Control: private, max-age=10 51 Expires: Tue, 11 Dec 2018 07:08:54 GMT 52 Last-Modified: Tue, 11 Dec 2018 07:08:44 GMT 53 X-UA-Compatible: IE=10 54 X-Frame-Options: SAMEORIGIN 55 56 ", Encoding.UTF8.GetByteCount(response)); 57 58 //返回给客户端 59 clientSocket.Send(Encoding.UTF8.GetBytes(responseHeader)); 60 clientSocket.Send(Encoding.UTF8.GetBytes(response)); 61 62 clientSocket.Close(); 63 } 64 65 }
Program.cs
class Program { static void Main(string[] args) { //浏览器访问127.0.0.1:8200/1.html WebServer.Start(); Console.ReadKey(); } }
1.html
<!DOCTYPE html> <html lang="en" xmlns="http://www.w3.org/1999/xhtml"> <head> <meta charset="utf-8" /> <title></title> </head> <body> <h1>这是1.html的内容</h1> </body> </html>
2.html
<!DOCTYPE html> <html lang="en" xmlns="http://www.w3.org/1999/xhtml"> <head> <meta charset="utf-8" /> <title></title> </head> <body> <h1>这是2.html的内容</h1> </body> </html>
效果:
自定义Middleware
文件结构
代码
MyStaticFileMiddleware.cs
public class MyStaticFileMiddleware { private readonly RequestDelegate _next; public MyStaticFileMiddleware(RequestDelegate next) { _next = next; } public Task Invoke(HttpContext context) { //1.logic 如果我当前的Context中有png,那么就直接从文件中读取,否则放下传递 var path = context.Request.Path.Value; if (path.Contains(".png")) { var mypath = path.Trim('/'); return context.Response.SendFileAsync(mypath); } var task = _next(context); return task; } }
Nginx反向代理
安装
命令:
sudo apt-get install nginx
因为是首次安装 Nginx,通过运行以下命令显式启动
sudo service nginx start
在浏览器地址栏中输入类似于 http://192.168.XXX.XXX
的IP地址或 http://域名
就可以显示 Nginx 的默认登陆页了。
配置 Nginx
若要将 Nginx 配置为转发请求向 ASP.NET Core 应用程序的反向代理,修改 /etc/nginx/sites-available/default 。 在文本编辑器中打开它,并将内容替换为以下内容:
server { listen 80; server_name test.com *.test.com; location / { proxy_pass http://localhost:5000; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection keep-alive; proxy_set_header Host $http_host; proxy_cache_bypass $http_upgrade; } }
Nginx 接受主机标头使用的端口 80 上的公共流量, Nginx 将匹配的请求转发到在 Kestrel http://localhost:5000
。
测试配置:
sudo nginx -t
显示结果如下所示:
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful
重新加载配置:
sudo nginx -s reload
Polly
github地址:https://github.com/App-vNext/Polly
使用
Install-Package Polly
代码
重试:RetryTest.cs
public class RetryTest { //重试策略的设定 public static void Run() { var retrayPloicy = Policy.Handle<WebException>() .WaitAndRetry(new List<TimeSpan>() { TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(3), TimeSpan.FromSeconds(5) }, (ex, dt) => { Console.WriteLine($"{DateTime.Now} {ex.Message} {dt} "); }); int count = 0; var html = retrayPloicy.Execute(() => { var url = "http://1cnblogs.com"; if (count == 3) url = "http://cnblogs.com"; return GetHtml(url, ref count); }); //这个是我调用第三次获取到的内容。。 Console.WriteLine(html); } /// <summary> /// 获取页面内容 /// </summary> /// <param name="url"></param> /// <returns></returns> public static string GetHtml(string url, ref int count) { var html = string.Empty; try { var webClient = new WebClient(); html = webClient.DownloadString(url); } catch (Exception ex) { count++; throw; } return html; } }
熔断:CircuitBreakderTest.cs
public class CircuitBreakderTest { public static void Run() { //如果当前连续有两个异常,那么触发熔断,10s内不能调用,10s之后重新调用。 //一旦调用成功了,熔断就解除了。 var policy = Policy.Handle<WebException>() .CircuitBreaker(2, TimeSpan.FromSeconds(10), (ex, timespan, context) => { //触发熔断 Console.WriteLine($"{DateTime.Now} 熔断触发:{timespan}"); }, (context) => { //恢复 Console.WriteLine($"{DateTime.Now} 熔断恢复"); }); var errCount = 1; for (int i = 0; i < 100; i++) { try { var msg = policy.Execute<string>((context, token) => { var url = "http://cnblogs1.com"; //模拟,当一定的时间后,恢复正常 if (errCount > 10) { url = "http://cnblogs.com"; } return GetHtml(url); }, new Dictionary<string, object>() { { i.ToString(), i.ToString() } }, CancellationToken.None); Console.WriteLine("logic:" + msg); } catch (Exception ex) { Console.WriteLine(string.Format("{0} 业务逻辑异常:'{1}'", DateTime.Now, ex.Message)); System.Threading.Thread.Sleep(2000); errCount++; } } } /// <summary> /// 获取页面内容 /// </summary> /// <param name="url"></param> /// <returns></returns> public static string GetHtml(string url) { var html = string.Empty; try { var webClient = new WebClient(); html = webClient.DownloadString(url).Substring(0, 10); } catch (Exception ex) { throw; } return html; } }
超时:TimeoutTest.cs
public class TimeoutTest { public static void Run() { var cancellationToken = new CancellationToken(); //10s后 cancellationToken过期 var policy = Policy.Timeout(10); //通过cancellationToken进行传值,如果10s过去,IsCancellationRequested 自动变成取消状态 policy.Execute((token) => { for (int i = 0; i < 1000; i++) { //大家需要根据这个状态来做具体的业务逻辑 Console.WriteLine(token.IsCancellationRequested); System.Threading.Thread.Sleep(1000); } }, cancellationToken); Console.Read(); } /// <summary> /// 获取页面内容 /// </summary> /// <param name="url"></param> /// <returns></returns> public static string GetHtml(string url) { var html = string.Empty; Thread.Sleep(20); return html; } }
隔离:BulkheadTest.cs
public class BulkheadTest { public static void Run() { var policy = Policy.Bulkhead(5, 1000); Parallel.For(0, 100, (i) => { //这里只能做一次调用 var result = policy.Execute<string>(() => { return GetHtml("http://cnblogs.com"); }); Console.WriteLine("已成功获取到数据:{0}", result); }); Console.Read(); } /// <summary> /// 获取页面内容 /// </summary> /// <param name="url"></param> /// <returns></returns> public static string GetHtml(string url) { var html = string.Empty; try { var webClient = new WebClient(); html = webClient.DownloadString(url); html = html.Substring(0, 17); Console.WriteLine($"当前线程ID={Thread.CurrentThread.ManagedThreadId}"); System.Threading.Thread.Sleep(2000); } catch (Exception ex) { throw; } return html; } }
回退:FallbackTest.cs
public class FallbackTest { public static void Run() { var result = Policy<string>.Handle<WebException>() .Fallback(() => { return "接口失败,这个fake的值给你!"; }) .Execute(() => { return GetHtml("http://1cnblogs.com"); }); Console.WriteLine(result); Console.Read(); } /// <summary> /// 获取页面内容 /// </summary> /// <param name="url"></param> /// <returns></returns> public static string GetHtml(string url) { var html = string.Empty; try { var webClient = new WebClient(); html = webClient.DownloadString(url); } catch (Exception ex) { throw; } return html; } }
c#7.0
out语法
//out { {//old string val = "10"; int result; int.TryParse(val, out result); Console.WriteLine(result); } {//new string val = "10"; int.TryParse(val, out int result); Console.WriteLine(result); } }
Tuple/ValueTuple
public static Tuple<bool, string> GetData() { return Tuple.Create(true, "操作成功"); } public static (bool, string) GetDataNew() { return (true, "操作成功"); } //Tuple { var tuple = GetData(); Console.WriteLine(tuple.Item1+" "+tuple.Item2); var (isSuccess, msg) = GetDataNew(); Console.WriteLine(isSuccess.ToString(),msg); }
Deconstruct(解构函数)
public class Person { private string _name; private int _age; public Person(string name, int age) { this._name = name; this._age = age; } public void Deconstruct(out string name, out int age) { name = this._name; age = this._age; } } //Deconstruct { var (Name, Age) = new Person("jack", 18); Console.WriteLine(Name + " " + Age); }
Local
//Local内部方法 { Console.WriteLine(GetLength("hello world")); int GetLength(string str) { return str.Length; } }
switch增强
//switch增强 { var list = new List<object>() { 1, "2" }; foreach (var item in list) { switch (item) { //如果当前item是int类型,那么执行 case int val: Console.WriteLine(val); break; //如果当前item是string类型,那么转成int case string str when int.TryParse(str, out int ival): Console.WriteLine(ival); break; default: break; } } }