前进中的蜗牛

番茄大叔

水滴穿石,非一日之功;没有量变,何来质变。

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));
  • 异步调用asyncawait
        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}"));
        }
posted @ 2018-11-07 16:06  LoveTomato  阅读(410)  评论(0编辑  收藏  举报