第四章 C#语言特性
内容:
?. ??
- 格式化字符串
- 初始化器
- Pattern Matching
- 扩展方法
- lambda表达式
- 匿名类行
- 异步操作
- 获取名称
使用Empty模板创建ASP.NET Core
空模板创建的项目,包括了最小的 ASP.NET Core configuration ,其中不包括MVC支持,所以需要添加点代码:
public class Startup {
public void ConfigureServices(IServiceCollection services) {
services.AddMvc();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env) {
if (env.IsDevelopment()) {
app.UseDeveloperExceptionPage();
}
//app.Run(async (context) => {
// await context.Response.WriteAsync("Hello World!");
//});
app.UseMvcWithDefaultRoute();
}
}
Null Conditional Operator ?.
string name = p?.Name; //若p为null,name==null; 否则 name = p.Name
decimal? price = p?.Price; //
string relatedName = p?.Related?.Name; //多个?. 链式使用
null coalescing operator ??
string name = p?.Name ?? "<No Name>"; //若 p?.Name 返回的是null,则 name = "<No Name>"; 否则name = p.Name
decimal? price = p?.Price ?? 0;
string relatedName = p?.Related?.Name ?? "<None>";
Automatically Implemented Properties
public string Name { get; set; }
public decimal? Price { get; set; }
public Product Related { get; set; }
public string Category { get; set; } = "Watersports"; // 自动属性+初始化
格式化字符串
string.Format("Name: {0}, Price: {1}, Related: {2}",name, price, relatedName)
$"Name: {name}, Price: {price}, Related: {relatedName}"
初始化器
Product kayak = new Product { //对象初始化
Name = "Kayak",
Category = "Water Craft",
Price = 275M
};
new string[] { "Bob", "Joe", "Alice" } //collection初始化
Dictionary<string, Product> products = new Dictionary<string, Product> { //字典初始化
{ "Kayak", new Product { Name = "Kayak", Price = 275M } },
{ "Lifejacket", new Product{ Name = "Lifejacket", Price = 48.95M } }
};
Dictionary<string, Product> products = new Dictionary<string, Product> { //更新的字典初始化方式
["Kayak"] = new Product { Name = "Kayak", Price = 275M },
["Lifejacket"] = new Product { Name = "Lifejacket", Price = 48.95M }
};
Pattern Matching
object[] data = new object[] { 275M, 29.95M,"apple", "orange", 100, 10 };
if (data[i] is decimal d) // 如果类型匹配,则值会给变量d
switch (data[i]) { //在switch中使用 pattern matching
case decimal decimalValue:
total += decimalValue;
break;
case int intValue when intValue > 50: // when 关键字来增加更多限制
total += intValue;
break;
}
Extension Method
public static decimal TotalPrices(this ShoppingCart cartParam) {
decimal total = 0;
foreach (Product prod in cartParam.Products) {
total += prod?.Price ?? 0;
}
return total;
}
// 给接口的扩展方法,这样所有实现这个接口的都可以使用
public static class MyExtensionMethods {
public static decimal TotalPrices(this IEnumerable<Product> products) {
decimal total = 0;
foreach (Product prod in products) {
total += prod?.Price ?? 0;
}
return total;
}
}
//使用`yield`关键字来过滤内容
//返回值要是 IEnumerable<...>
public static IEnumerable<Product> FilterByPrice(this IEnumerable<Product> productEnum, decimal minimumPrice) {
foreach (Product prod in productEnum) {
if ((prod?.Price ?? 0) >= minimumPrice) {
yield return prod;
}
}
}
Lambda Expressions
prod => EvaluateProduct(prod) /单参数,单语句
(prod, count) => prod.Price > 20 && count > 0 //多参数
(prod, count) => { //多参数,多语句
// ...multiple code statements...
return result;
}
//对方法使用lambda--- 当方法或者constructor中只有一条语句的时候
public ViewResult Index() => View(Product.GetProducts().Select(p => p?.Name));
//对property使用lambda
public bool NameBeginsWithS => Name?[0] == 'S'; //只有get的属性
类型推断和匿名类型
var names = new [] { "Kayak", "Lifejacket", "Soccer ball" }; //implicit type
var name = new {Name= "", Age = ""};
异步方法
直接和Task
打交道
public static Task<long?> GetPageLength() {
HttpClient client = new HttpClient();
var httpTask = client.GetAsync("http://apress.com");
return httpTask.ContinueWith((Task<HttpResponseMessage> antecedent) => {
return antecedent.Result.Content.Headers.ContentLength;
});
}
.NET把每个异步执行的任务表示为Task
, Task
是强类型的,都是和最终返回什么类型的结果相关。 所以当HttpClient.GetAsync
调用的时候,会返回一个Task<HttpResponseMessage>
,这个类型意思是, 这个在后台进行的异步任务最终会返回一个HttpResponseMessage
对象作为结果。
一般让人迷惑的地方在于 Continuation
。ContinueWith
方法用来处理当Task完成之后,应该做什么操作。
第一个return代表 GetPageLength
方法立即返回一个 Task<HttpResponseMessage
对象; 第二个在return代表这个Task完成后最后返回的内容。
使用async
和await
public async static Task<long?> GetPageLength() {
HttpClient client = new HttpClient();
var httpMessage = await client.GetAsync("http://apress.com");
return httpMessage.Content.Headers.ContentLength;
}
public async Task<ViewResult> Index() {
long? length = await MyAsyncMethods.GetPageLength();
return View(new string[] { $"Length: {length}" });
}
获取名称 nameof
表达式
不是硬编码,而是让编译器来针对属性,类型等等,来产生对应的名字
$"{nameof(p.Name)}: {p.Name}, {nameof(p.Price)}: {p.Price}"));