C#之路

C#1.0

  • 结构
  • 接口
  • 事件
  • 属性
  • 委托
  • 表达式
  • 语句
  • 特性
  • 文本

注意:委托与类同级,可以把委托理解成方法声明,当一个方法想用方法作参数时,这时就可以用委托【只是一种应用场景】

委托与事件的区别,事件可以当成一种特殊的委托,主要区别在触发执行上,普通委托声明可以被外部其他类触发执行,而事件只能在自身声明类中执行,两者都可以在外部绑定委托方法,另外事件绑定只能通过+=,委托+,+=都可以

  class Program
    {

        static void Main(string[] args)
        {

            Student student = new Student();

            student.handler1 = Ouput;// 委托
            student.handler1 += Ouput;
            student.handle2 += Ouput;// 事件

            student.handler1();
            student.handle2.Invoke(); // 错误写法
            student.ExeEvent();       // 正确写法
        }

        static string Ouput()
        {
            Console.WriteLine("1");
            return "";
        }
    }

    public delegate string DelHandler();
    public class Student
    {
        public DelHandler handler1;
        public event DelHandler handle2;

        public void ExeEvent()
        {
            if (handle2 != null)
            {
                handle2.Invoke();
            }
        }
    }

  

 C#2.0

  • 泛型
        public class GenericList<T>
        {
            public void Add(T input) { }
            public T Get(int index) { return default(T); }
        }
    

      T就是泛型,泛指一类对象类型,T可以是int,string也可以是你自己定义的类,一般用于统一输入,输出

  • 分布类型
  • 匿名方法
            static void Main(string[] args)
            {
    
                DelHandler student = Ouput;// 正常绑定委托
    
                student += delegate ()  // 匿名委托
                {
                    return "";
                };
            }
    
            static string Ouput()
            {
                Console.WriteLine("1");
                return "";
            }

    匿名方法主要用于委托绑定,好处是不需要创建一个独立的方法

  • 可以为null的类型
  • 迭代器
    static void Main()  
    {  
        foreach (int number in SomeNumbers())  
        {  
            Console.Write(number.ToString() + " ");  
        }  
        // Output: 3 5 8  
        Console.ReadKey();  
    }  
    
    public static System.Collections.IEnumerable SomeNumbers()  
    {  
        yield return 3;  
        yield return 5;  
        yield return 8;  
    }  

    foreach遍历的对象必须是继承IEnumerable接口的,接口配合关键字yield返回集合值,上面的SomeNumbers是一个方法直接返回IEnumerable类型,如果SomeNumber是一个类,则需要实现IEnumerable的GetEnumerator方法

        class Program
        {
            static void Main(string[] args)
            {
                SomeNumbers someNumbers = new SomeNumbers();
                foreach (int number in someNumbers)
                {
                    Console.Write(number.ToString() + " ");
                }
                // Output: 3 5 8  
                Console.ReadKey();
            }
        }
        public class SomeNumbers : IEnumerable
        {
            public IEnumerator GetEnumerator()
            {
                yield return 3;
                yield return 5;
                yield return 8;
            }
        }
  • 协变和逆变
        class Program
        {
            static void Main(string[] args)
            {
                // string【子类】 是继承 object【父类】
                string str = "abc";
                object obj = str; // 协变【正常变化】  子类->父类
    
                str = (string)obj;// 逆变【非正常变化,容易报错】  父类->子类
                str = (string)new object(); // 会报错
            }
        }

    对象由子类转父类就是协变【正常变化】

    对象由父类转子类就是逆变

C#3.0

  • 自动实现的属性
  • 匿名类型
    var v = new { Amount = 108, Message = "Hello" };  
    
    // Rest the mouse pointer over v.Amount and v.Message in the following  
    // statement to verify that their inferred types are int and string.  
    Console.WriteLine(v.Amount + v.Message);  

    和匿名方法一样,不需要声明一个类就可以初始一个对象出来

  • 查询表达式
    static void Main()
    {
        // Data source.
        int[] scores = { 90, 71, 82, 93, 75, 82 };
    
        // Query Expression.
        IEnumerable<int> scoreQuery = //query variable
            from score in scores //required
            where score > 80 // optional
            orderby score descending // optional
            select score; //must end with select or group
    
        // Execute the query to produce the results
        foreach (int testScore in scoreQuery)
        {
            Console.WriteLine(testScore);
        }                  
    }
    // Outputs: 93 90 82 82

    查询表达式是以查询语法表示的查询。 查询表达式是一流的语言构造。 它如同任何其他表达式一样,可以在 C# 表达式有效的任何上下文中使用。 查询表达式由一组用类似于 SQL 或 XQuery 的声明性语法所编写的子句组成。 每个子句进而包含一个或多个 C# 表达式,而这些表达式可能本身是查询表达式或包含查询表达式。

  • Lambda表达式
        class Program
        {
            static void Main(string[] args)
            {
                List<Person> persons = new List<Person>();
                persons = persons.Where(p => p.Age > 6).ToList();       //所有Age>6的Person的集合
    
                Func<Person, bool> func = p => p.Age > 6;               // Lambda表达式
                persons = persons.Where(func).ToList();                 // 和上面同一个意思
            }
        }
        public class Person
        {
            public string Name { get; set; }
            public int Age { get; set; }
        }

    Lambda 表达式是一种可用于创建 委托 或 表达式目录树 类型的 匿名函数 。 通过使用 lambda 表达式,可以写入可作为参数传递或作为函数调用值返回的本地函数,lambda 表达式 x => x * x 指定名为 x 的参数并返回 x 的平方值

  • 表达式树
        class Program
        {
            static void Main(string[] args)
            {
                Expression<Func<int, int>> expr = x => x + 1;
                expr.Compile().Invoke(1);                                            // 编译时解析
                Expression<Func<int, int, int>> expr2 = (x, y) => { return x + y; }; // 报错 无法将具有语句块【可以理解为不能用大括号】的lambda表达式转换为表达式树 
            }
        }

    表达式树是在运行时解析表达式树生成相应匿名方法,注意:无法将具有语句块的lambda表达式转换为表达式树

  • 扩展方法
  • 隐式类型本地变量
  • 分部方法
        class Program
        {
            static void Main(string[] args)
            {
                A t = new A();
                t.Exe();
            }
        }
        partial class A
        {
            partial void OnSomethingHappened(string s);
    
            public void Exe()
            {
                OnSomethingHappened("aa");
            }
        }
    
        // This part can be in a separate file.
        partial class A
        {
            // Comment out this method and the program
            // will still compile.
            partial void OnSomethingHappened(string s)
            {
                Console.WriteLine("Something happened: {0}", s);
            }
        }

    分部方法必须在分部类中,其中一个是签名,另一个是实现,返回值必须是void【注定外面不能直接调取,不知道这个特性有什么意义】

  • 对象和集合初始值设定项
    List<Cat> cats = new List<Cat>
    {
        new Cat(){ Name = "Sylvester", Age=8 },
        new Cat(){ Name = "Whiskers", Age=2 },
        new Cat(){ Name = "Sasha", Age=14 }
    };
    var numbers = new Dictionary<int, string> {   
        [7] = "seven",   
        [9] = "nine",   
        [13] = "thirteen"   
    };  

C#4.0

  • 动态绑定
        class Program
        {
            static void Main(string[] args)
            {
                dynamic t = new A(); // 运行时解析
                t.Exe();
            }
        }
        public class A
        {
            public void Exe()
            {
                Console.WriteLine("aa");
            }
        }

    该类型的作用是绕过编译时类型检查。 改为在运行时解析这些操作。

  • 命名参数/可选参数
        class Program
        {
            static void Main(string[] args)
            {
                A t = new A();                         
                t.Exe(b: "bb", a: "aa");                // 参数可以不按顺序写
            }
        }
        public class A
        {
            public void Exe(string a, string b, string c = "")// c可选参数
            {
                Console.WriteLine("aa");
            }
        }
  • 泛型协变和逆变
      class Program
        {
            static void Main(string[] args)
            {
                // 泛型中 in 代表逆变【参数】 out 代表协变【返回】 in,out只能定义在接口中
                // 接口IEnumerable是协变 IComparable是逆变
    
                // 协变
                // List<Base> b1 = new List<Derived>();       // 报错 List不支持协变【List中的T不是out】
                IEnumerable<Derived> d = new List<Derived>(); // 由子类【List】转父类【IEnumerable】
                IEnumerable<Base> b = d;                      // 再协变一次 由子类【Derived】转父类【Base】  
    
                // 逆变 逆变更注重执行时参数传入
                List<Circle> circles = new List<Circle> { new Circle(), new Circle(), null, new Circle() };
                ShapeAreaComparer comparer = new ShapeAreaComparer();  // 定义父类shape
                circles.Sort(comparer);// 因为主体是List<Circle>【子类】 所以执行到这参数类型应该是IComparer<Circle> 执行时comparer会由shape会转成circle 
            }
        }
        public interface A1<in T>// 正确写法 in 只能在接口或委托 并当参数用
        {
            void Exe(T a);
        }
        public interface A2<in T>// 错误写法
        {
            T Exe(int a);
        }
        public interface B1<out T>// 正确写法 out 只能在接口或委托 并当返回值用
        {
            T Exe(int a);
        }
        public interface B2<out T>// 错误写法
        {
            void Exe(T a);
        }
        public class Base { }// 父类
        public class Derived : Base { }    // 子类
        abstract class Shape // 父类
        {
            public virtual double Area { get { return 0; } }
        }
        class Circle : Shape// 子类
        {
            public override double Area { get { return Math.PI; } }
        }
        class ShapeAreaComparer : System.Collections.Generic.IComparer<Shape> // 逆变接口
        {
            int IComparer<Shape>.Compare(Shape a, Shape b)
            {
                if (a == null) return b == null ? 0 : -1;
                return b == null ? 1 : a.Area.CompareTo(b.Area);
            }
        }

     委托中Func和Action也是

        class Program
        {
            public static Derived MyMethod(Base b)
            {
                return b as Derived ?? new Derived();
            }
            static void Main(string[] args)
            {
                Func<Base, Derived> f1 = MyMethod; // 初始类型
    
                Func<Base, Base> f2 = f1;
                Base b2 = f2(new Base());       // b2协变 返回类型由子类->父类
    
                Func<Derived, Derived> f3 = f1;
                Derived d3 = f3(new Derived()); // d3逆变 参数由父类->转子类【在方法中执行】
            }
        }
    
        public class Base { }
        public class Derived : Base { }

    协变和逆变在于对象引用地址的变更

  • 嵌入的互操作类型

C#5.0

  • 异步成员
  • 调用方信息特性
            static void Main(string[] args)
            {
                TraceMessage("msg");
            }
    
            static void TraceMessage(string message,
             [System.Runtime.CompilerServices.CallerMemberName] string memberName = "",
             [System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "",
             [System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0)
            {
                System.Diagnostics.Trace.WriteLine("message: " + message);
                System.Diagnostics.Trace.WriteLine("member name: " + memberName);
                System.Diagnostics.Trace.WriteLine("source file path: " + sourceFilePath);
                System.Diagnostics.Trace.WriteLine("source line number: " + sourceLineNumber);
            }

     

C#6.0

  • 静态导入
  • 异常筛选器
  • 属性初始值设定
  • Expression Bodied成员
  • Null传播器
  • 字符串内插
  • nameof运算符
  • 索引初始值设定项

C#7.0

  • Out变量
  • 元组和析构函数
  • 模式匹配
  • 本地函数
  • 已扩展expression bodied成员
  • ref局部变量和返回结果

C#7.1

  • async Main方法
  • default文本表达式
  • 推断元组元素名称

C#7.2

  • 引用语义结合值类型
  • 非尾随命名参数
  • 数字文字中的前导下划线
  • private protected访问修饰符

C#7.3

  • 无需固定即可访问固定的字段
  • 可以重新分配ref本地变量
  • 可以使用stackalloc数组上的初始值设定项
  • 可以对支持模式的任何类型使用fixed语句
  • 可以使用其他泛型约束
  • 可以使用元组类型测试==和!=
  • 可以在多个位置使用表达式变量
  • 可以将属性附加到自动实现的属性的支持字段
  • 由in区分的参数的方法解析得到了改进
  • 重载解析的多义情况现在变得更少

 

posted @ 2018-09-06 17:11  小09牛  阅读(185)  评论(0)    收藏  举报