序言
C# 1.0 (2002)
public interface IDateProvider { DateTime GetDate(); }
隐式接口实现
public class DefaultDateProvider : IDateProvider { public DateTime GetDate() { return DateTime.Now; } }
显式接口实现
显式接口实现的一个很好的方面是它强制消费者依赖于接口。显式实现接口的实例对象必须使用接口本身,而没有其他可用的接口成员!
public class MinDateProvider : IDateProvider { DateTime IDateProvider.GetDate() { return DateTime.MinValue; } }
通过直接使用接口,不会将代码耦合到底层实现。
IDateProvider provider = new MinDateProvider();
C# 2.0 (2005)
泛型(Generics)
为什么要有泛型?
我们在写一些方法时可能会方法名相同,参数类型不同的方法,这种叫做重载。如果只是因为参数类型不同里面做的业务逻辑都是相同的,那可能就是复制粘贴方法,改变参数类型,例如一些排序算法,int、float、double等类型的排序,参数数组存的数据类型不一样,还有像根据索引找到List集合中的对象。可能这个对象是
Person、Dog等对象,这样方法改变的只是参数类型,那就是能不能写一个方法,传递不同的参数类型呢?于是乎有了泛型。
什么是泛型?
泛型通过参数化类型来实现在同一份代码上操作多种数据类型。例如使用泛型的类型参数T,定义一个类Stack<T>,可以用Stack<int>、Stack<string>或Stack<Person>实例化它,从而使类Stack可以处理int、string、Person类型数据。这样可以避免运行时类型转换或封箱操作的代价和风险,类似C++的模板。泛型提醒的是将
具体的东西模糊化,这与后面的反射正好相反。
有几种编写泛型类型参数约束的方法,请考虑以下语法:
public class DataBag where T : struct { /* T 值类型 */ } public class DataBag where T : class { /* T 类、接口、委托、数组 */ } public class DataBag where T : new() { /* T 有无参构造函数 */ } public class DataBag where T : IPerson { /* T 继承 IPerson */ } public class DataBag where T : BaseClass { /* T 派生自 BaseClass */ } public class DataBag where T : U { /* T 继承 U, U 也是一个泛型参数 */ }
多个约束是允许的,用逗号分隔。类型参数约束立即生效,即编译错误阻止程序员犯错。
C# 3.0 (2007)
匿名类型
var person1 = new { Name = "learning hard", Age = 25 };
自动实现的属性
/// <summary> /// 姓名 /// </summary> public string Name { get; set; }
表达树
扩展方法
public static class ExtensionMethod { public static void ShowItems<T>(this IEnumerable<T> colletion) { foreach (var item in colletion) { if (item is string) { Console.WriteLine(item); } else { Console.WriteLine(item.ToString()); } } } }
调用扩展方法
"123123123123".ShowItems();//字符串 new[] { 1, 2, 3, 4, }.ShowItems();//int数组 new List<int> { 1, 2, 3, 4 }.ShowItems();//List容器
Lambda表达
static List<int> GetSquaresOfPositiveByLambda(List<string> strList) { return strList .Select(s => Int32.Parse(s)) // 转成整数 .Where(i => i % 2 == 0) // 找出所有偶数 .Select(i => i * i) // 算出每个数的平方 .OrderBy(i => i) // 按照元素自身排序 .ToList(); // 构造一个List }
查询表达式
C# 4.0 (2010)
动态绑定
嵌入式互操作类型
泛型中的协变和逆变
命名/可选参数
可选参数允许为方法的一些参数提供默认值,并允许使用者重载类型,因此,即使只有一个方法,也能处理所有变体
public void test(string a, string b, int c, bool d=true,bool e=false) { }
调用:
public void invoke() { test("li", "dd",7); test("li", "dd", 7,false); test("li", "dd", 7, true,false); }
C# 5.0 (2012)
异步/等待
Console.WriteLine("主线程开始"); Task<string> task = Task<string>.Run(() => { Thread.Sleep(1000); return Thread.CurrentThread.ManagedThreadId.ToString(); }); Console.WriteLine(task.Result); Console.WriteLine("主线程结束");
调用方信息
C# 6.0 (2015)
字典初始化
class StudentName { public string FirstName { get; set; } public string LastName { get; set; } public int ID { get; set; } } class CollInit { Dictionary<int, StudentName> students = new Dictionary<int, StudentName>() { { 111, new StudentName {FirstName="Sachin", LastName="Karnik", ID=211}}, { 112, new StudentName {FirstName="Dina", LastName="Salimzianova", ID=317}}, { 113, new StudentName {FirstName="Andy", LastName="Ruth", ID=198}} }; }
异常过滤器
try { } catch (Exception) { } finally { }
表达式体成员
nameof 操作符
Console.WriteLine(nameof(Int32));
空合并运算符
??被称为【可空合并】运算符,是一个二目运算符,操作参数两枚,其完成的功能为对左参数判断之后进行赋值。
返回结果:如果左操作数不为空,则返回左操作数本身;如果左操作书为空,则返回右操作数。
格式:object1 ?? object2
int? x = null; int y = x ?? -1; Console.WriteLine(string.Format("x={0},y={1}", x, y));
属性初始化
class Person { public string Name { get; set; } public int Age { get; set; } public string Address { get; set; } } Person person = new Person { Name = "Slark", Age = 100, Address = "Xi'an" }; List<int> intList = new List<int> { 1, 2, 3 }; List<Person> personList = new List<Person> { new Person { Name = "Slark1", Age = 101, Address = "Xi'an1" }, new Person { Name = "Slark2", Age = 102, Address = "Xi'an2" }, new Person { Name = "Slark3", Age = 103, Address = "Xi'an3" } };
静态引用
字符串插值
编程中经常用到字符串的拼接。
class Plane { public string Category { get; set; } public string Name { get; set; } public int State { get; set; } }
C#6.0之前的方法:
var p = new Plane() { Category = "A", Name = "B", State = 0 }; var sb=new StringBuilder(); sb.Append(string.Format("Category={0},Name={1},State={2}",plan.Category,plane.Name,plane.State);
C#6.0之后的方法:
var p = new Plane() { Category = "A", Name = "B", State = 0 }; var sb=new StringBuilder(); sb.Append($"Category={p.Category},Name={p.Name},State={p.State}");
C# 7.0 (2017)
表达式体成员
局部方法
Out 变量
模式匹配
static dynamic Add(object a) { dynamic data; switch (a) { case int b: data=b++; break; case string c: data= c + "aaa"; break; default: data = null; break; } return data; }
匹配模式的Case When筛选
switch (a) { case int b when b < 0: data = b + 100; break; case int b: data=b++; break; case string c: data= c + "aaa"; break; default: data = null; break; }
局部引用和引用返回
public static void DoSomeing() { //调用Dosmeing2 int data = Dosmeing2(100, 200); Console.WriteLine(data); //定义局部函数,Dosmeing2. int Dosmeing2(int a, int b) { return a + b; } }
元组
static void Main(string[] args) { var data = GetFullName(); Console.WriteLine(data.Item1); Console.WriteLine(data.Item2); Console.WriteLine(data.Item3); Console.ReadLine(); } static Tuple<string, string, string> GetFullName() { return new Tuple<string, string, string>("a", "b", "c"); }
解构元组
有的时候我们不想用var匿名来获取,那么如何获取abc呢?我们可以如下:
static void Main(string[] args) { //定义解构元组 (string a, string b, string c) = GetFullName(); Console.WriteLine(a); Console.WriteLine(b); Console.WriteLine(c); Console.ReadLine(); } private static (string a,string b,string c) GetFullName() { return ("a","b","c"); }
https://www.cnblogs.com/microsoft-zyl/p/9093748.html