我是靠谱客的博主 英勇大米,最近开发中收集的这篇文章主要介绍C#学习日记19,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

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

public static class GuidEx
{
    public static bool IsGuid(string value)
    {
        Guid x;
        return Guid.TryParse(value, out x);
    }
}

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

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[正则表达式]

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提交:

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提交即可:

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语句:

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如下所示:

static void Main(string[] args)
{
    var channel = Channel.CreateUnbounded<string>();
}

创建Boundedchannel使用FullMode:

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:

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:

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例子

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
解析:实现一个扩展方法如下所示:

public static class Extensions
{
    public static HashSet<T> ToHashSet<T>(this IEnumerable<T> source, IEqualityComparer<T> comparer = null)
    {
        return new HashSet<T>(source, comparer);
    }
}

应用扩展方法如下所示:

var query = from i in Enumerable.Range(0, 10)
            select new { i, j = i + 1 };
var resultSet = query.ToHashSet();

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

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中已经支持:

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

IQueryable query = from x in appEntities
where x.id == 32
select x;
var sql = ((System.Data.Objects.ObjectQuery)query).ToTraceString();

[2]方法2:EF6

var sql = ((System.Data.Entity.Core.Objects.ObjectQuery)query).ToTraceString();

[3]方法3:EF6.3

var sql = ((dynamic)flooringStoresProducts).Sql;

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

var query = context.Set<Customer>().Where(c => c.City == city);
Console.WriteLine(query.ToQueryString())

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

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():

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

public static bool CheckURLValid(this string source)
{
    Uri uriResult;
    return Uri.TryCreate(source, UriKind.Absolute, out uriResult) && uriResult.Scheme == Uri.UriSchemeHttp;
}

[2]方法2

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做自定义验证
解析:

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:

public static string ToHexString(byte[] inArray);
public static byte[] FromHexString(string s);

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

[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

[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

[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来停止应用程序。

[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:

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.程序集
解析:

namespace DemoXUnit
{
    public class Program
    {
        public static void Main() {
            Console.WriteLine(typeof(Program));
            Console.WriteLine(typeof(Program).Assembly);
        }
    }
}

输出结果如下所示:

DemoXUnit.Program
DemoXUnit, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null

20.制作Nuget包
解析:

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],可以在运行时动态获取运算逻辑。

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只是存储了结果,无法保存成语法树,也无法动态获取运算逻辑。

Func<User, bool> func1 = x => x.Age > 18;
dbContext.User.Where(func1).toList();

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

最后

以上就是英勇大米为你收集整理的C#学习日记19的全部内容,希望文章能够帮你解决C#学习日记19所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

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

评论列表共有 0 条评论

立即
投稿
返回
顶部