C# 语法新特性
下面介绍下C#的新语法,这些新语法使编程更方便快捷(往往一行代码能起到老语法几行功能),同时也更健壮减少异常发生,方便阅读。个人认为很有必要掌握下。
环境准备
新建一个Product
类 和 ShoppingCart
public class Product
{
public string Name { get; set; }
public string Category { get; set; } = "Waterports";
public decimal? Price { get; set; }
public Product Related { get; set; }
public bool InStock { get; } = true;
public bool NameBeginsWithS => Name?[0] == 'S';
public static Product[] GetProduct()
{
Product kayak = new Product
{
Name = "Kayak",
Category="Water Craft",
Price = 275M
};
Product lifejacket = new Product
{
Name = "Lifejacket",
Price = 48.95M
};
kayak.Related = lifejacket;
return new Product[] { kayak, lifejacket, null };
}
}
public class ShoppingCart:IEnumerable<Product>
{
public IEnumerable<Product> Products { get; set; }
public IEnumerator<Product> GetEnumerator()
{
return Products.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
新语法介绍
- null 条件符(?) 语义:只有当对象不为null时才访问对象属性
public HomeController
{
public ViewResult Index()
{
List<string> results = new List<string>();
foreach (Product p in Product.GetProduct())
{
string name = p?.Name ?? "<No Name>";
decimal? price = p?.Price ?? 0;
string relatedName = p?.Related?.Name ?? "<None>";
results.Add(string.Format($"Name:{name},Price{price},Related:{relatedName}"));
}
return View(results);
}
}
- null 合并符(??) 语义:当??操作符左侧为null则返回右侧值,否则放回左侧。
decimal? price = p?.Price ?? 0;
- 属性设置初始值,在声明属性时可以为属性设置初始值
public string Category { get; set; } = "Waterports";
- 设置read-only属性初始值(有两种方法,另一种在构造函数中设置)
public bool InStock { get; } = true;
- 字符串中插入变量值,这种时字符串拼接更简单,格式$+字符串
$"Name:{name},Price{price},Related:{relatedName}"
- 对象和集合的初始化
//对象初始化
Product kayak = new Product
{
Name = "Kayak",Category="Water Craft",Price = 275M
};
//数组类初始化
string[] names = new string[] { "Bob", "Joe", "Alice" };
//字典初始化
Dictionary<string, Product> products = new Dictionary<string, Product>
{
["Kayak"]=new Product { Name = "Kayak",Category = "Water Craft"},
["Lifejacket"]=new Product { Name = "Lifejacket", Category = "Water Craft" }
};
- 类型检测符(
is
) 分析if(data[i] is decimal d)
如果data[i]
的类型是decimal
则返回true
并给d
变量赋值,在switch
语句中同样可以使用
public ViewResult Total()
{
object[] data = new object[] { 275M, 29.95, "apple", "orange", 100, 10 };
decimal total = 0;
for(int i = 0; i < data.Length; i++)
{
if(data[i] is decimal d)
{
total += d;
}
}
return View($"Total:{total:C2}");
}
- 扩展方法,通过扩展方法为现有类型添加方法,使调用更方便(注意:1.类为静态类,2方法为静方法 3.第一个参数 this 被扩展类型)
public static class ShoppingCartExtension
{
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 ShoppingCartExtension
{
public static decimal TotalPrices(this IEnumerable<Product> products)
{
decimal total = 0;
foreach (Product prod in products)
{
total += prod?.Price ?? 0;
}
return total;
}
}
- 使用Lambde表达式表达条件,这样调用端更灵活
public static class ShoppingCartExtension
{
//过滤表达式
public static IEnumerable<Product> Filter(this IEnumerable<Product> productEnum, Func<Product, bool> selector)
{
foreach (Product prod in productEnum)
{
if (selector(prod))
{
yield return prod;
}
}
}
}
调用更灵活
//根据name过滤
IEnumerable<Product> ProductsbyName =Product.GetProduct().Filter(p => p?.Name?[0] == 'S');
//或者根据价格过滤
IEnumerable<Product> ProductsbyPrice =Product.GetProduct().Filter(p => (p?.Price ?? 0) > 30);
- Lambda初始化属性或函数
//初始化属性
public bool NameBeginsWithS => Name?[0] == 'S';
//初始化函数
public ViewResult ProductsName() => View(Product.GetProduct().Select(p => p?.Name));
- 异步调用
async
和await
public async static Task<long?> GetPageLength2()
{
HttpClient client = new HttpClient();
var httpMessage = await client.GetAsync("https://baidu.com");
return httpMessage.Content.Headers.ContentLength;
}
在调用该方法
public async Task<ViewResult> GetPageLength()
{
long? length = await AsyncMethods.GetPageLength2();
return View($"Length:{length}");
}
nameof()
获取表达式的变量的字符串形式(为当前变量名添加双引号""
),这样避免hard code忘了更新。
public ViewResult Products()
{
var products = new[] {
new {Name="Kayak",Price=275M},
new {Name="Lifejacket",Price=48.95M},
new {Name="Soccer ball",Price=19.50M},
new {Name="Corner flag",Price=34.95M},
};
//return View(products.Select(p => $"Name:{p.Name},{Price:{p.Price}"));
//同上 避免更改了属性名忘记更改 hard code`Name`和`Price`
return View(products.Select(p => $"{nameof(p.Name)}:{p.Name},{nameof(p.Price)}:{p.Price}"));
}