下面是本身总结的一些C#语言方面用的少容易忘的地方,总结一下,在用的时候看一下。(仅针对本人)数组
定义一个函数,用来取得数字的和,可是数字的个数不肯定。app
解决方案: 1,定义一个函数,参数传递过来一个数组; 2,定义一个参数个数不肯定的函数,这个时候咱们就要使用参数数组。ide
参数数组相比于数组参数的区别:params函数
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 namespace _050_参数数组__定义一个参数个数不肯定的函数_ { 8 class Program { 9 //若是一个函数定义了参数,那么在调用这个函数的时候,必定要传递对应类型的参数,不然没法调用(编译器编译不经过) 10 static int Sum(int[] array) 11 { 12 int sum = 0; 13 for (int i = 0; i < array.Length; i++) 14 { 15 sum += array[i]; 16 } 17 return sum; 18 } 19 20 //这里定义了一个int类型的参数数组,参数数组和数组参数(上面的)的不一样, 21 //在于函数的调用,调用参数数组的函数的时候,咱们能够传递过来任意多个参数, 22 //而后编译器会帮咱们自动组拼成一个数组,参数若是是上面的数组参数,那么这个数组咱们本身去手动建立 23 static int Plus(params int[] array) 24 { 25 int sum = 0; 26 for (int i = 0; i < array.Length; i++) { 27 sum += array[i]; 28 } 29 return sum; 30 } 31 static void Main(string[] args) 32 { 33 int sum = Sum(new int[] {23, 4, 34, 32, 32, 42, 4}); 34 Console.WriteLine(sum); 35 int sum2 = Plus(23, 4, 5, 5, 5, 32, 423, 42, 43,23,42,3);//参数数组就是帮咱们 减小了一个建立数组的过程 36 Console.WriteLine(sum2); 37 Console.ReadKey(); 38 } 39 } 40 }
委托(delegate)是一种存储函数引用的类型。this
委托的定义很简单,声明一个函数,而后在前面加上 delegate 关键字,这样就声明了一个委托spa
委托的使用分两步:声明,定义3d
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace _053_委托的使用 { //定义一个委托跟函数差很少,区别在于 //1,定义委托须要加上delegate关键字 //2,委托的定义不须要函数体 public delegate double MyDelegate(double param1, double param2); class Program { static double Multiply(double param1, double param2) { return param1*param2; } static double Divide(double param1, double param2) { return param1/param2; } static void Main(string[] args) { MyDelegate de;//利用咱们定义的委托类型声明了一个新的变量 de = Multiply;//当咱们给一个委托的变量赋值的时候,返回值跟参数列表必须同样,不然没法赋值 Console.WriteLine(de(2.0, 34.1)); de = Divide; Console.WriteLine( de(2.0,34.1) ); Console.ReadKey(); } } }
Action委托:返回值为void,参数能够为0个或多个 Action[<param...>] xxx = 某函数code
Func委托:有一个返回值,参数能够为0个或多个 Func<[param...],returnType> xxx = 某函数对象
多播委托:就是定义一个委托后,不止绑定某一个函数,使用+=,-=符号来添加删除绑定的函数。要注意的是,多播委托中,中间若是某一个函数执行出错,后面的都不会执行blog
委托的使用:好比要定义一个针对学生名及学生成绩的排序(也多是其它状况),之前的排序方法,须要咱们针对不一样的状况写不一样的排序方法。如今有了委托后,咱们能够传入一个类型不定的数组,传入一个委托类型的排序方法,在这个排序方法中写好排序就行。
1 namespace _007_冒泡排序拓展 { 2 class Employee { 3 public string Name { get; private set; } 4 public int Salary { get; private set; } 5 6 public Employee(string name, int salary) 7 { 8 this.Name = name; 9 this.Salary = salary; 10 } 11 //这里定义了一个针对Employee的比较方法 12 public static bool Compare(Employee e1, Employee e2) 13 { 14 if (e1.Salary > e2.Salary) return true; 15 return false; 16 } 17 18 public override string ToString() 19 { 20 return Name + ":" + Salary; 21 } 22 } 23 }
1 namespace _007_冒泡排序拓展 { 2 class Program {
//这里定义了一个通用的排序方法 3 static void CommonSort<T>(T[] sortArray, Func<T,T,bool> compareMethod) 4 { 5 bool swapped = true; 6 do { 7 swapped = false; 8 for (int i = 0; i < sortArray.Length - 1; i++) { 9 if (compareMethod(sortArray[i],sortArray[i+1])) { 10 T temp = sortArray[i]; 11 sortArray[i] = sortArray[i + 1]; 12 sortArray[i + 1] = temp; 13 swapped = true; 14 } 15 } 16 } while (swapped); 17 } 18 static void Main(string[] args) { 19 Employee[] employees = new Employee[] 20 { 21 new Employee("dsf",12), 22 new Employee("435dsf",234), 23 new Employee("234dsf",14), 24 new Employee("ds234f",234), 25 new Employee("dssfdf",90) 26 }; 27 CommonSort<Employee>(employees,Employee.Compare); 28 foreach (Employee em in employees) 29 { 30 Console.WriteLine(em); 31 } 32 Console.ReadKey(); 33 } 34 } 35 }
Lambda表达式:凡是能用委托表达的都能使用Lambda表达式来表达,反正式子中有这玩意"=>",也没见用这玩意咋样,还要难理解些,不用,谁用谁煞笔
事件:事件是基于委托的,有了委托才会有事件。下面举一个例子,有两个类,丈夫和妻子,妻子类有个方法是看丈夫在玩游戏没,丈夫类有个方法是观察妻子的动向。在以往的写法中,每当妻子调用她的方法后,丈夫也要调用自身的方法,这样在本例中还算好的,若是换成其它的一对多的关系,那么代码量会很大,且维护起来很麻烦。有了委托后(注意,这里说的仍是委托,尚未用到事件),咱们在建立丈夫后,将丈夫的方法绑定到妻子的一个委托上,这样妻子每次检查时丈夫都会观察到并执行相应函数。
1 namespace ConsoleApp1 2 { 3 class Wife//妻子 4 { 5 //这里声明一个委托用来绑定丈夫的观察函数 6 public Action bindfunc; 7 public void Coming() 8 { 9 Console.WriteLine("妻子:去看看老公在玩游戏没"); 10 if(bindfunc != null) 11 { 12 bindfunc(); 13 } 14 } 15 } 16 }
1 namespace ConsoleApp1 2 { 3 class Husband//丈夫 4 { 5 public Husband(Wife wife) 6 { 7 // 在构造丈夫的时候,就把自身的函数绑定到妻子的delegate上 8 wife.bindfunc = See; 9 } 10 11 public void See() 12 { 13 Console.WriteLine("丈夫:盯到看到,媳妇来老"); 14 } 15 } 16 }
1 namespace ConsoleApp1 2 { 3 class Program 4 { 5 static void Main(string[] args) 6 { 7 Wife wife = new Wife(); 8 Husband husband = new Husband(wife); 9 wife.Coming(); 10 } 11 } 12 }
嗯嗯,关于事件event,它就是把上面在妻子中声明的委托 public Action bindfunc 改为 public event Action bindfunc,就是加了个event表示而已,那它有啥做用呢。若是不用event标识,那妻子中的委托bindfunc咱们可使用妻子的实例随手调用,用event声明后,它就是一个事件,不能随手用。
咱们习惯上把类中的字段设置为私有的,这样外接不可以修改字段的值,而后咱们经过定义属性来设置和取得字段中的值
1 private int age; 2 public int Age 3 { 4 set{age = value;} 5 get{return age;} 6 }
从上面能够看到,属性包含两个块,get块和set块。访问属性和访问字段同样,当取得属性的值的时候,就会调用属性中的get块,因此get块,当咱们去给属性设置值的时候,就会调用属性中的set块
属性须要注意的地方:
1:、另外,set块和get块能够只提供一个(两个都不提供也行,那至关于该属性没有用),若是只提供set块表示只写,只提供get块表示只读
二、set块和get块能够设置为私有的,设置为私有的块只能在类的内部访问(固然该属性也能够设置为私有,这样该属性只能在类的内部使用)
1 public string name 2 { 3 private set{name = value;} 4 get{return name;} 5 }
三、咱们也能够不用建立字段,直接设置属性,这样编译器会帮咱们自动建立
1 public int Age{get;set;}
四、属性相对于之前单首创建函数来设置和获取字段值,不一样是它能够在设置的时候,作一些须要的操做,好比判断
1 public int Age 2 { 3 set 4 { 5 if(value > 0) 6 age = value; 7 } 8 }
虚方法:在父类中使用virtual关键字声明函数,在子类中使用override关键字声明该函数
隐藏方法:不适用virtual关键字和override关键字声明
定义2个类,Enemy和Boss,Boss继承自Enemy
1 class Enemy 2 { 3 public void Run() 4 { 5 print("父类Run"); 6 } 7 public virtual void Eat() 8 { 9 print("父类Eat"); 10 } 11 }
1 class Boss:Enemy 2 { 3 public void Run() 4 { 5 print("子类Run"); 6 } 7 public override void Eat() 8 { 9 print("子类Eat"); 10 } 11 }
1 class Test 2 { 3 static void Main(string[] args) { 4 Enemy e1 = new Boss(); 5 e1.Run(); //父类Run 6 e1.Eat(); //子类Eat 7 8 Boss b1 = new Boss(); 9 b1.Run(); //子类Run 10 b1.Eat(); //子类Eat 11 } 12 }
能够看到,若是是隐藏方法,那么若是使用父类声明子对象,调用的方法仍是父类的方法。由于,隐藏方法只是隐藏,父类中的方法还在。
若是是虚方法,那么调用后都是执行子类中的代码。由于,虚方法重写后父类中的方法就不存在了。
使用虚方法还有一个重要的做用,那就是当声明一个函数的时候,若是当时并不知道具体的实现,只知道之后子类会用到它,那么咱们能够先把它声明为虚方法,等着之后子类去实现。
1 class Test 2 { 3 public void Use() 4 { 5 UseThis(); 6 } 7 public virtual void UseThis() 8 { 9 } 10 }
抽象类其实和前边说的虚方法有关。虚方法中,用virtual关键字声明后,在子类中能够重写也能够不重写。抽象类使用abstract关键字声明函数(注意:函数使用abstract声明后,那么类自动称为抽象类,也须要使用abstract声明,编译器会提示的),子类中必须使用关键字override实现该函数。
注意,抽象类能够声明子类对象,可是不能直接使用抽象类实例化对象。
1 abstract class Test 2 { 3 public abstract void Use(); 4 }
接口是特殊的抽象类,在抽象类中能够定义字段和普通的方法,可是在接口中只能定义方法,且不容许提供接口中任何成员的实现方式,不容许声明成员修饰符,接口中的成员都是共有的。
说白了,接口中就是声明了一些公有方法,让继承该接口的子类本身去实现。
1 public interface Test 2 { 3 public void Use(); 4 public void Do(); 5 ... 6 }