我是靠谱客的博主 英勇大米,这篇文章主要介绍C#学习日记19,现在分享给大家,希望可以做个参考。

1.判断某个字符串是否为合法的GUID
解析:
[1]方法1[Guid.Parse或Guid.TryParse]

复制代码
1
2
3
4
5
6
7
8
9
public static class GuidEx { public static bool IsGuid(string value) { Guid x; return Guid.TryParse(value, out x); } }

[2]方法2[.NET4.0之前版本,构造函数]

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public static bool TryParseGuid(string guidString, out Guid guid) { if (guidString == null) throw new ArgumentNullException("guidString"); try { guid = new Guid(guidString); return true; } catch (FormatException) { guid = default(Guid); return false; } }

[3]方法3[正则表达式]

复制代码
1
2
3
4
5
6
7
8
9
10
11
public static bool IsGUID(string expression) { if (expression != null) { Regex guidRegEx = new Regex(@"^({{0,1}([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}}{0,1})$"); return guidRegEx.IsMatch(expression); } return false; }

2.在Dapper中使用事务
解析:
[1]简单的事务方法
在已存在的Connection上创建Transaction,然后将事务作为参数传递到Execute方法中,当业务逻辑处理完后,再做commit提交:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
string sql = "INSERT INTO Customers (CustomerName) Values (@CustomerName);" using (var connection = new SqlConnection(FiddleHelper.GetConnectionStringSqlServerW3Schools())) { connection.Open(); using (var transaction = connection.BeginTransaction()) { connection.Execute(sql, new {CustomerName = "Mark"}, transaction: transaction); connection.Execute(sql, new {CustomerName = "Sam"}, transaction: transaction); connection.Execute(sql, new {CustomerName = "John"}, transaction: transaction); transaction.Commit(); } }

[2]使用TransactionScope
在connection创建之前创建Scope,然后在Scope作用域内做想做的sql操作,最后执行一个complete提交即可:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
using (var transaction = new TransactionScope()) { var sql = "INSERT INTO Customers (CustomerName) Values (@CustomerName);"; using (var connection = My.ConnectionFactory()) { connection.Open(); connection.Execute(sql, new {CustomerName = "Mark"}); connection.Execute(sql, new {CustomerName = "Sam"}); connection.Execute(sql, new {CustomerName = "John"}); } transaction.Complete(); }

[3]使用Dapper Transaction方式
可以直接在new出的Transaction之上执行各自的sql语句:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
string sql = "INSERT INTO Customers (CustomerName) Values (@CustomerName);"; using (var connection = new SqlConnection(FiddleHelper.GetConnectionStringSqlServerW3Schools())) { connection.Open(); using (var transaction = connection.BeginTransaction()) { transaction.Execute(sql, new {CustomerName = "Mark"}); transaction.Execute(sql, new {CustomerName = "Sam"}); transaction.Execute(sql, new {CustomerName = "John"}); transaction.Commit(); } }

3.System.Threading.Channels
解析:
[1]创建channel
可以创建两种类型的channel,一种是有限容量的bound channel,一种是无限容量的unbound channel。Channels提供了两种工厂方法用于创建:CreateBounded<T>创建的channel是一个有消息上限的通道。CreateUnbounded<T>创建的channel是一个无消息上限的通道。创建unbounded channel如下所示:

复制代码
1
2
3
4
5
static void Main(string[] args) { var channel = Channel.CreateUnbounded<string>(); }

创建Boundedchannel使用FullMode:

复制代码
1
2
3
4
5
6
7
8
static void Main(string[] args) { var channel = Channel.CreateBounded<string>(new BoundedChannelOptions(1000) { FullMode = BoundedChannelFullMode.Wait }); }

FullMode属性用于指定当channel已满时该如何对插入的message进行处理,通常有四种做法:Wait,DropWrite,DropNewest,DropOldest。
[2]将消息写入到channel
使用WriteAsync()方法将message写入到channel:

复制代码
1
2
3
4
5
6
7
8
9
10
static async Task Main(string[] args) { var channel = Channel.CreateBounded<string>(new BoundedChannelOptions(1000) { FullMode = BoundedChannelFullMode.Wait }); await channel.Writer.WriteAsync("Hello World!"); }

[3]从channel中读取消息
使用ReadAsync()从channel中读取message:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
static async Task Main(string[] args) { var channel = Channel.CreateBounded<string>(new BoundedChannelOptions(1000) { FullMode = BoundedChannelFullMode.Wait }); while (await channel.Reader.WaitToReadAsync()) { if (channel.Reader.TryRead(out var message)) { Console.WriteLine(message); } } }

[4]System.Threading.Channels例子

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Program { static async Task Main(string[] args) { await SingleProducerSingleConsumer(); Console.ReadKey(); } public static async Task SingleProducerSingleConsumer() { var channel = Channel.CreateUnbounded<int>(); var reader = channel.Reader; for (int i = 0; i < 10; i++) { await channel.Writer.WriteAsync(i + 1); } while (await reader.WaitToReadAsync()) { if (reader.TryRead(out var number)) { Console.WriteLine(number); } } } }

说明:实现生产者-消费者场景,可以使用BlockingCollection,TPL Dataflow,或者Channels[性能更高]。

4.EasyCaching.SQLite
解析:基于磁盘的缓存解决方案。参考资料:https://easycaching.readthedocs.io/en/latest/SQLite/#2-config-in-startup-class

5.将Linq的查询结果转为HashSet
解析:实现一个扩展方法如下所示:

复制代码
1
2
3
4
5
6
7
8
public static class Extensions { public static HashSet<T> ToHashSet<T>(this IEnumerable<T> source, IEqualityComparer<T> comparer = null) { return new HashSet<T>(source, comparer); } }

应用扩展方法如下所示:

复制代码
1
2
3
4
var query = from i in Enumerable.Range(0, 10) select new { i, j = i + 1 }; var resultSet = query.ToHashSet();

除了使用扩展方法,也可以用HashSet<T>构造函数:

复制代码
1
2
3
4
var query = from i in Enumerable.Range(0, 10) select new { i, j = i + 1 }; var resultSet = new HashSet<int>(query);

ToHashSet扩展方法在.NETFramework 4.7.2和.NET Core 2.0中已经支持:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public static HashSet<TSource> ToHashSet<TSource>(this IEnumerable<TSource> source) { return source.ToHashSet(null); } public static HashSet<TSource> ToHashSet<TSource>(this IEnumerable<TSource> source, IEqualityComparer<TSource> comparer) { if (source == null) { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.source); } return new HashSet<TSource>(source, comparer); }

6.捕获EF生成的SQL脚本
解析:
[1]方法1

复制代码
1
2
3
4
5
IQueryable query = from x in appEntities where x.id == 32 select x; var sql = ((System.Data.Objects.ObjectQuery)query).ToTraceString();

[2]方法2:EF6

复制代码
1
2
var sql = ((System.Data.Entity.Core.Objects.ObjectQuery)query).ToTraceString();

[3]方法3:EF6.3

复制代码
1
2
var sql = ((dynamic)flooringStoresProducts).Sql;

[4]方法4:EF Core 5.0
可以直接调用Query的ToQueryString()方法:

复制代码
1
2
3
var query = context.Set<Customer>().Where(c => c.City == city); Console.WriteLine(query.ToQueryString())

7.当前线程等待所有线程执行完
解析:
[1].NET4.0+

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Program { static void Main(string[] args) { Task task1 = Task.Factory.StartNew(() => doStuff()); Task task2 = Task.Factory.StartNew(() => doStuff()); Task task3 = Task.Factory.StartNew(() => doStuff()); Task.WaitAll(task1, task2, task3); Console.WriteLine("All threads complete"); } static void doStuff() { //do stuff here } }

[2].NET4.0-
可以使用BackgroundWorker,ThreadPool.QueueUserWorkItem()或者手工调用Thread.Join():

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
static void Main(string[] args) { Thread t1 = new Thread(doStuff); t1.Start(); Thread t2 = new Thread(doStuff); t2.Start(); Thread t3 = new Thread(doStuff); t3.Start(); t1.Join(); t2.Join(); t3.Join(); Console.WriteLine("All threads complete"); }

8.判断一个string是否为有效的url格式
解析:
[1]方法1:Uri.TryCreate

复制代码
1
2
3
4
5
6
public static bool CheckURLValid(this string source) { Uri uriResult; return Uri.TryCreate(source, UriKind.Absolute, out uriResult) && uriResult.Scheme == Uri.UriSchemeHttp; }

[2]方法2

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public static bool ValidHttpURL(string s, out Uri resultURI) { if (!Regex.IsMatch(s, @"^https?://", RegexOptions.IgnoreCase)) s = "http://" + s; if (Uri.TryCreate(s, UriKind.Absolute, out resultURI)) return (resultURI.Scheme == Uri.UriSchemeHttp || resultURI.Scheme == Uri.UriSchemeHttps); return false; } string[] inputs = new[] { "https://www.google.com", "http://www.google.com", "www.google.com", "google.com", "javascript:alert('Hack me!')" }; foreach (string s in inputs) { Uri uriResult; bool result = ValidHttpURL(s, out uriResult); Console.WriteLine(result + "t" + uriResult?.AbsoluteUri); }

9.通过AuthorizeAttribute做自定义验证
解析:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Startup { public void ConfigureServices(IServiceCollection services) { services.Configure<AuthorizationOptions>(options => { options.AddPolicy("ManageStore", policy => policy.RequireClaim("Action", "ManageStore")); }); } } public class StoreController : Controller { [Authorize(Policy = "ManageStore"), HttpGet] public async Task<IActionResult> Manage() { ... } }

10.byte[]和十六进制互转
解析:可以使用Convert下新增的两个方法ToHexString和FromHexString:

复制代码
1
2
3
public static string ToHexString(byte[] inArray); public static byte[] FromHexString(string s);

11.ASP.Net Core Web API返回File
解析:
[1]方法1:返回FileStreamResult

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
[HttpGet("get-file-stream/{id}"] public async Task<FileStreamResult> DownloadAsync(string id) { var fileName="myfileName.txt"; var mimeType="application/...."; Stream stream = await GetFileStreamById(id); return new FileStreamResult(stream, mimeType) { FileDownloadName = fileName }; }

[2]方法2:返回FileContentResult

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
[HttpGet("get-file-content/{id}"] public async Task<FileContentResult> DownloadAsync(string id) { var fileName="myfileName.txt"; var mimeType="application/...."; byte[] fileBytes = await GetFileBytesById(id); return new FileContentResult(fileBytes, mimeType) { FileDownloadName = fileName }; }

[3]方法3:ActionResult+File

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
[Route("api/[controller]")] public class DownloadController : Controller { //GET api/download/12345abc [HttpGet("{id}")] public async Task<IActionResult> Download(string id) { Stream stream = await {{__get_stream_based_on_id_here__}} if(stream == null) return NotFound(); // returns a NotFoundResult with Status404NotFound response. return File(stream, "application/octet-stream"); // returns a FileStreamResult } }

12.通过调用接口关闭应用程序
解析:通过注入IHostApplicationLifetime然后执行StopApplication来停止应用程序。

复制代码
1
2
3
4
5
6
[HttpGet] public void StopApplication([FromServices] IHostApplicationLifetime lifetime) { lifetime.StopApplication(); }

13.JWT和OAuth2比较
解析:JWT是一种认证协议,JWT提供了一种用于发布接入令牌(Access Token),并对发布的签名接入令牌进行验证的方法。令牌(Token)本身包含了一系列声明,应用程序可以根据这些声明限制用户对资源的访问;OAuth2是一种授权框架另一方面,OAuth2是一种授权框架,提供了一套详细的授权机制。用户或应用可以通过公开的或私有的设置,授权第三方应用访问特定资源。

14.ViewBag
解析:ViewBag是一个dynamic类型的对象,可以用来在controller和页面之间传递数据。

15.绑定源参数推理
解析:绑定源特性定义可找到操作参数值的位置:
[1][FromBody]:请求正文。针对复杂类型参数进行推断。
contentType:“application/json”
[2][FromForm]:请求正文中的表单数据。针对IFormFile和IFormFileCollection类型的操作参数进行推断。推断multipart/form-data请求内容类型。
contentType: “application/x-www-form-urlencoded”
[3][FromHeader]:请求标头
[4][FromQuery]:请求查询字符串参数。针对任何其它操作参数进行推断。
[5][FromRoute]:当前请求中的路由数据。针对与路由模板中的参数相匹配的任何操作参数名称进行推断。
[6][FromServices]:作为操作参数插入的请求服务

16.禁用推理规则
解析:在Startup.ConfigureServices中将SuppressInferBindingSourcesForParameters设置为true:

复制代码
1
2
3
4
5
6
7
8
9
10
11
services.AddControllers() .ConfigureApiBehaviorOptions(options => { options.SuppressConsumesConstraintForFormFileParameters = true; options.SuppressInferBindingSourcesForParameters = true; options.SuppressModelStateInvalidFilter = true; options.SuppressMapClientErrors = true; options.ClientErrorMapping[StatusCodes.Status404NotFound].Link = "https://httpstatuses.com/404"; });

17.form-data和x-www-form-urlencoded区别
解析:
[1]multipart/form-data:既可以上传文件等二进制数据,也可以上传表单键值对,只是最后会转化为一条信息。
[2]x-www-form-urlencoded:只能上传键值对,并且键值对都是间隔分开的。

18.GroupBy()方法
解析:GroupBy()方法参数是分组条件表达式,返回值为IGrouping<TKey,TSource>类型的泛型IEnumerable,即每一组以一个IGrouping对象的形式返回。IGrouping是一个继承自IEnumerable的接口,IGrouping中Key属性表示这一组的分组数据的值。

19.程序集
解析:

复制代码
1
2
3
4
5
6
7
8
9
10
11
namespace DemoXUnit { public class Program { public static void Main() { Console.WriteLine(typeof(Program)); Console.WriteLine(typeof(Program).Assembly); } } }

输出结果如下所示:

复制代码
1
2
3
DemoXUnit.Program DemoXUnit, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null

20.制作Nuget包
解析:

复制代码
1
2
dotnet pack [--output] [--no-build] [--build-base-path] [--configuration] [--version-suffix] [<project>]

dotnet pack命令生成项目并创建NuGet包。这个操作的结果是两个nupkg扩展名的包。一个包含代码,另一个包含调试符号。

21.虚方法和虚属性
解析:virtual关键字用于修饰方法、属性、索引器或事件声明,并使它们可以在派生类中被重写。

22.base关键字
解析:base关键字用于从派生类中访问基类的成员。

23.[NotNull]和[CanBeNull]特性
解析:在System.Diagnostics.CodeAnalysis里面定义的NotNull和CanBeNull特性。

24.NET表达式目录树
解析:表达式树以树形数据结构表示代码,其中每一个节点都是一种表达式。

25.Expression和Func区别
解析:在EFCore中,使用表达式对数据库数据进行查询中,应该选择Expression而不是Func,因为使用了Func,实际上并无法将Func中的表达式转换成SQL,而是在将所有数据加载到内存后,在内存中在过滤Func中的条件。
[1]Expression存储了运算逻辑,可以将其保存成抽象语法树[AST],可以在运行时动态获取运算逻辑。

复制代码
1
2
3
Expression<Func<User,bool>> expression1 = x => x.Age > 18; dbContext.User.Where(expression1).toList();

上述代码生成的SQL语句:SELECT * FROM User as T WHERE T.age > 18。
[2]Func只是存储了结果,无法保存成语法树,也无法动态获取运算逻辑。

复制代码
1
2
3
Func<User, bool> func1 = x => x.Age > 18; dbContext.User.Where(func1).toList();

上述代码生成的SQL语句:SELECT * FROM User,然后将User表中所有数据加载到内存中后,再进行age>18的过滤。

最后

以上就是英勇大米最近收集整理的关于C#学习日记19的全部内容,更多相关C#学习日记19内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(75)

评论列表共有 0 条评论

立即
投稿
返回
顶部