zoukankan      html  css  js  c++  java
  • C#易忘点

    下面是自己总结的一些C#语言方面用的少容易忘的地方,总结一下,在用的时候看一下。(仅针对本人)

    参数数组

    定义一个函数,用来取得数字的和,但是数字的个数不确定。

    解决方案: 1,定义一个函数,参数传递过来一个数组; 2,定义一个参数个数不确定的函数,这个时候我们就要使用参数数组。

    参数数组相比于数组参数的区别: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)是一种存储函数引用的类型。

    委托的定义很简单,声明一个函数,然后在前面加上 delegate 关键字,这样就声明了一个委托

    委托的使用分两步:声明,定义

    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 = 某函数

    Func委托:有一个返回值,参数可以为0个或多个    Func<[param...],returnType> xxx = 某函数

    多播委托:就是定义一个委托后,不止绑定某一个函数,使用+=,-=符号来添加删除绑定的函数。要注意的是,多播委托中,中间如果某一个函数执行出错,后面的都不会执行

    委托的使用:比如要定义一个针对学生名及学生成绩的排序(也可能是其它情况),以前的排序方法,需要我们针对不同的情况写不同的排序方法。现在有了委托后,我们可以传入一个类型不定的数组,传入一个委托类型的排序方法,在这个排序方法中写好排序就行。

     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块表示只读

    2、set块和get块可以设置为私有的,设置为私有的块只能在类的内部访问(当然该属性也可以设置为私有,这样该属性只能在类的内部使用)

    1 public string name
    2 {
    3     private set{name = value;}
    4     get{return name;}
    5 }

    3、我们也可以不用创建字段,直接设置属性,这样编译器会帮我们自动创建

    1 public int Age{get;set;}

    4、属性相对于以前单独创建函数来设置和获取字段值,不同是它可以在设置的时候,做一些需要的操作,比如判断

    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 }
  • 相关阅读:
    bert源码的文件、参数理解
    除了利用打印的方法保存colab,如何直接转化为图片(附使用tf自己预训练模型导入办法)
    sse、mse、rmse、 r-square
    我的开源之旅(也许中道崩卒哈哈哈)
    attention_utils无法导入
    那些天,shell脚本中曾经踩过的坑
    python通过webservice接口实现配置下发
    python源文件转换成exe问题解决贴
    suds库使用说明官方文档
    两个实用linux小工具
  • 原文地址:https://www.cnblogs.com/lmx282110xxx/p/10764703.html
Copyright © 2011-2022 走看看