概述
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所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复