c#杂记
LINQ
-
linq分为方法语法和查询语法(和sql语句相似,微软推荐)
-
EF 查询的两种 写法。 linq 方法 或者 lambda方法,其中 ,只有tolist()的时候,才会真正的 在数据库中执行。如果没有 tolist 方法,那么province1是 iqueable类型
委托
-
声明一个委托,其实就是个“命令”
-
Delegate至少0个参数,至多32个参数,可以无返回值,也可以指定返回值类型。这个是祖宗。
-
Func可以接受0个至16个传入参数,必须具有返回值。
-
Action可以接受0个至16个传入参数,无返回值。
-
Predicate只能接受一个传入参数,返回值为bool类型。
// 委托多播实例:例如小明叫小张买完车票,之后接着又让他带张电影票:
// 小张类
public class MrZhang
{
// 其实买车票的悲情人物是小张
public static void BuyTicket()
{
Console.WriteLine("NND,每次都让我去买票,鸡人呀!");
}
public static void BuyMovieTicket()
{
Console.WriteLine("我去,自己泡妞,还要让我带电影票!");
}
}
//小明类
class MrMing
{
// 声明一个委托,其实就是个“命令”
public delegate void BugTicketEventHandler();
public static void Main(string[] args)
{
// 这里就是具体阐述这个命令是干什么的,本例是MrZhang.BuyTicket“小张买车票”
BugTicketEventHandler myDelegate = new BugTicketEventHandler(MrZhang.BuyTicket);
myDelegate += MrZhang.BuyMovieTicket;
// 这时候委托被附上了具体的方法
myDelegate();
Console.ReadKey();
}
}
-
接口是为了实现共同的标准;抽象是为了代码的复用。当然,接口和抽象,都可以实现里氏替换。
-
我们在设计架构的时候,使用的EF的时候往往会在参数调用的时候放一个Expression<Func<T, bool>>表示参数。
-
Func<TObject, bool> 是 一个参数为 TObject 类型的参数 返回值为bool 类型的匿名函数
-
Func<TObject, bool>是委托(delegate), Expression<Func<TObject, bool>>是表达式, Expression编译后就会变成delegate,才能运行。
// Func<TObject, bool> 是 一个参数为 TObject 类型的参数 返回值为bool 类型的匿名函数
Func<string, bool> func = delegate(string s) {
return true;
};
拓展方法
参数中带this的原因
public static class StringExtension
{
public static void Foo(this string s)
{
Console.WriteLine("Foo invoked for {0}", s);
}
}
-
为什么这里会有一个this关键字,做什么用?其实这就是扩展方法!这个扩展方法在静态类中声明,定义一个静态方法,其中第一个参数定义可它的扩展类型。Foo()方法扩展了String类,因为它的第一个参数定义了String类型,为了区分扩展方法和一般的静态方法,扩展方法还需要给第一个参数使用this关键字。
-
现在就可以使用带string类型的Foo方法了:
-
string s="Hello"; s.Foo();
-
结果在控制台上显示Foo invoked for Hello ,因为Hello是传送给Foo方法的字符串。
-
归纳:扩展方法可以写入最初没有提供该方法的类中。还可以把方法添加到实现某个接口的任何类中,这样多个类可以使用相同的实现代码。
-
例子:
// 有没有想过要检查一个字符串变量是否是个合法的电子邮件地址? 在今天,你大概需要通过调用一个单独的类(或许通过一个静态方法)来实现检查该字符串变量是否合法。譬如,象这样:
string email = Request.QueryString["email"];
if ( EmailValidator.IsValid(email) ) {
}
// 而使用C#中的新“扩展方法”语言特性的话,我则可以添加一个有用的“IsValidEmailAddress()”方法到string类本身中去,该方法返回当前字符串实例是否是个合法的字符串。然后我可以把我的代码重写一下,使之更加干净,而且更具描述性,象这样:
string email = Request.QueryString["email"];
if ( email.IsValidEmailAddress() ) {
}
多线程 异步编程
[Route("api/[controller]")]
public class ValuesController : Controller
{
// GET: api/<controller>
[HttpGet("get")]
public async Task<string> Get()
{
var info = string.Format("api执行线程:{0}", Thread.CurrentThread.ManagedThreadId);
var infoTask = await TaskCaller();//使用await
var infoTaskFinished = string.Format("api执行线程(task调用完成后):{0}", Thread.CurrentThread.ManagedThreadId);
return string.Format("{0},{1},{2}", info, infoTask, infoTaskFinished);
}
private async Task<string> TaskCaller()
{
await Task.Delay(5000);
return string.Format("task 执行线程:{0}", Thread.CurrentThread.ManagedThreadId);
}
}
/*
* 结果为 [ api执行线程9,task执行线程:10,api执行线程(task调用完成后):9 ]
* 一开始运行在线程10,后来跳到async方法中执行在线程8中,在没有使用await时,主线程并没有停下来,还是按照自己的路往下走,
* 直到async使用了await方法,下面的代码也是交给了子线程。
*/
-
线程 被定义为程序的执行路径
-
异步编程是对于多线程来说的,通过创建不同线程来实现多个任务的并行执行。
-
尽量不混合使用同步和异步代码,要异步就异步到底,不然可能会因为异常捕获、死锁等原因导致应用程序崩溃。好文推荐
-
默认创建的Thread是前台线程,创建的Task为后台线程。