C# 知识点总结

入门

C#程序在.NET上运行,.NET framework包含两个部分:
①:.NET framework类库
②:公共语言运行库CLR(.NET虚拟机)
CLS(公共语言规范) CTS(通用类型系统)
.NET 还包含大量库,这些库支持多种不同的工作负载。

编译工具:

使用visual studio code 新建控制台,进入终端(Ctrl+~),选择好文件存储位置之后,输入dotnet命令即可;

dotnet new console  //新建控制台应用

使用visual studio 2022 新建项目,选择控制台(.NET Framwork);

using System;
class Program 
{ static void Main() { Console.WriteLine("Hello, World!");         }  
}

请看大屏幕,程序员入门之向世界说你好,
Main静态方法是C#程序的入口点。

所有代码都必须包含在类中,类的文件后缀名为.cs,最上面是using,然后是命名空间→类→属性和方法→代码块;

数据类型

C#中有两大类,值类型和引用类型

值类型

包含数据的实际值,而不是引用。类似于Java中的四类八种,这里就不一一例举了,可以百度下。

引用类型

存储了一个指向对象的引用,包括常见的类、字符串、数组、接口、委托、Null,dynamic等。

类型判断

使用var关键字,可以根据变量的初始化值"推断"变量的类型。

例如:

var a=0;
就变成
int a=0;

var定义的类型是静态的,在编译时候就被定义好了。

而dynamic定义的是动态类型,它在程序运行的时候才会确定。

值类型(Value Types)和引用类型(Reference Types)的区别

值类型:

1.直接存储数据的实际值,存储在栈(Stack)中,且内存分配和释放是⾃动完成的。每个值类型的变量都具有⾃⼰的内存空间,互相独⽴。

2.当⼀个值类型的变量被赋值给另⼀个变量,实际上是将该值的副本复制给了新变量。因此,修改⼀个变量不会影响到其他变量,它们互相独⽴。(纸张的复印,修改复印件不会影响本件)。

3.当将值类型的变量作为⽅法的参数进⾏传递时,实际上是将值的副本传递给了⽅法。在⽅法内部对参数的修改不会影响到原始变量。

4.值类型适⽤于较⼩的简单数据,具有快速的访问和复制特性。

引用类型:

1.存储的事对象的引用,也就是内存地址,对象本身存储在堆(Heap)中,多个引⽤类型的变量可以指向同⼀个对象,它们共享同⼀块内存空间。

2.当⼀个引⽤类型的变量被赋值给另⼀个变量,实际上是将对象的引⽤复制给了新变量。因此,两个变量引⽤同⼀个对象,修改其中⼀个变量会影响到另⼀个变量,它们共享同⼀块内存空间。(同⼀个云盘资源,使⽤不同链接分享给不同的⼈时,⼤家看到的资源是同⼀个资源,如果这个资源被修改了,⼤家看到的都变化了)。

3.当将引⽤类型的变量作为⽅法的参数进⾏传递时,实际上是将对象的引⽤传递给了⽅法。在⽅法内部对参数引⽤的对象进⾏的修改会影响到原始变量。

4.引⽤类型适⽤于复杂的对象、⼤型数据集合和需要共享数据的场景,但需要更多的内存开销和额外的访问层级。

装箱和拆箱

装箱和拆箱的过程就是将值类型和引用类型互相转换的过程,但是实际开发中尽量避免出现装箱和拆箱,为什么?因为损耗性能,可以使用泛型来避免。

//装箱
int number=20;
object obj=number;
//拆箱
int numberss=(int)obj;

运算符

这里也不一一介绍了,所有开发语言的运算符基本一致,极个别除外;

运算法优先级

优先级简易概括:有括号先括号,后乘除在加减,然后位移再关系,逻辑完后条件,最后⼀个逗号,。

字符串处理

字符串拼接

常规字符串处理就是定义两个string,然后拼接;

string firstName = "Taylor";string lastName = "Swift";Console.WriteLine(firstName + lastName);
//输出TaylorSwift

但是有没有想过,如果N个字符拼接呢,要写N个?那么性能呢?C#中为了提高程序性能,提供了StringBuilder方法进行拼接。

StringBuilder btf = new SreingBuilder();btf.Append("Taylor");btf.Append("Swift");Console.WriteLine(btf);
//输出TaylorSwift

字符串格式化

string.Format:

string firstName = "Taylor";string lastName = "Swift";string result = string.Format("first name is {0}, last name is {1}", firstName, lastName); Console.WriteLine(result);
//输出TaylorSwift

 交互

输出用WriteLine,输入呢?ReadLine。

string btf = Console.ReadLine();Console.WriteLine(btf);

 分支和循环

分支

if、if else if、switch分支

分支同Java、Python、Shell一样的。

循环

for、foreach、while、do...while循环

循环也是,foreach循环式当做集合使用(个人理解)和for没有什么区别

int[] arr = {1,2,3,4,5};foreach (int var in arr)
{Console.WriteLine(var);
}

 枚举

枚举是值类型C#中,不能被继承

//定义枚举DayofWeek 
enum DayofWeek{Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday}static void Main() { Console.WriteLine("Day of the week: " + DayofWeek.Monday);        }  

还有一种调用,如果报错因为层级的关系将实例化放在枚举上边即可。

 enum DayofWeek{Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday}DayofWeek DayofWeekEnum = DayofWeek.Monday;

 结构体

public struct Person
{//定义两个字段public string Name;public int Age;
} static void Main(string[] args) {Person person = new Person();//实例化
//赋值person.Name = "test";person.Age = 18;
//打印Console.WriteLine(person.Name);Console.WriteLine(person.Age);}    

 结构的特点:

结构可带有⽅法、字段、索引、属性、运算符⽅法和事件。

结构可定义构造函数,但不能定义析构函数。但是,不能为结构定义⽆参构造函数。⽆参构造函数(默认)是⾃动定义的,且不能被改变。

结构不能作为其他结构或类的基础结构。结构可实现⼀个或多个接⼝。结构成员不能指定为abstract、virtual或protected。当使⽤New操作符创建⼀个结构对象时,会调⽤适当的构造函数来创建结构。与类不同,结构可以不使⽤ New操作符即可被实例化。如果不使⽤New操作符,只有在所有的字段都被初始化之后,字段才被赋值,对象才被使⽤。

方法

功能:

代码重用

调用:类的实例.⽅法名([参数列表])静态⽅法:类名.⽅法名([参数列表])

方法分为有参和无参

static void Main() {代码块}
//Main方法(无参)static void Main(){
static void Ma(int a,int b) {Console.WriteLine($"{a},{b}");
}    int c =10;int d=20;Ma(c,d);
}
//有参

 异常处理

和Java、Python中的异常一样,try final finally

C#中 try、catch、finally、throw

try:⼀个try块标识了⼀个将被激活的特定的异常的代码块。后跟⼀个或多个catch块。

catch:程序通过异常处理程序捕获异常。catch关键字表⽰异常的捕获。

finally:finally块⽤于执⾏给定的语句,不管异常是否被抛出都会执⾏。例如,如果您打开⼀个⽂件,不管是否出现异常⽂件都要被关闭。

throw:当问题出现时,程序抛出⼀个异常。使⽤ throw 关键字来完成。

try
{一起异常的语句}
catch(异常(Exception(异常基类)) e)
{处理异常}
finally
{执行语句代码块}

*面向对象* 

面向对象是一种编程范式,使程序更加灵活,容易修改,易于复⽤。

它将现实世界的概念和实体表⽰为程序中的对象。

在⾯向对象编程中,程序由⼀组相互作⽤的对象组成,每个对象都有⾃⼰的状态(属性)和⾏为(⽅法)。

⾯向对象编程的核⼼思想是将复杂的问题分解为⼀系列相对独⽴的对象,这些对象通过相互发送消息来协同⼯作。

每个对象都可以封装⾃⼰的数据和功能,并且可以与其他对象进⾏交互。

1.类(Class):类是对象的模板或蓝图,描述了对象的属性和⽅法。它定义了对象的结构和⾏为。

2.对象(Object):对象是类的实例。每个对象都有⾃⼰的状态和⾏为。

.3封装(Encapsulation):封装是⼀种将数据和⽅法组合在⼀起的机制,以限制对对象内部数据的直接访问。通过封装,对象的内部细节对外部是隐藏的,只能通过对象的公共接⼜访问。

4.继承(Inheritance):继承是⼀种机制,允许创建⼀个新类(⼦类)来继承现有类(⽗类)的属性和⽅法。⼦类可以重⽤⽗类的代码,并可以在不修改⽗类的情况下扩展其功能。

5.多态(Polymorphism):多态允许以统⼀的⽅式使⽤不同类的对象。它使得可以在⽗类的引⽤下操作⼦类的对象,通过⽅法的重写和⽅法的重载实现多态性。

类的定义是以关键字class开始,后跟类的名称。类的主体,包含在⼀对花括号内。 (使用.访问类的成员)。

访问修饰符

1.public:公共访问修饰符,表⽰成员可以从任何地⽅访问,没有限制。

2.private:私有访问修饰符,表⽰成员只能在同⼀类中访问,对外部代码不可⻅。3.protected:受保护访问修饰符,表⽰成员可以在同⼀类内部和派⽣类中访问,对外部代码不可⻅。

4.internal:内部访问修饰符,表⽰成员可以在同⼀程序集中访问。程序集是指⼀组相关的代码⽂件(通常是⼀个项⽬或⼀个库),可以是单个项⽬或多个项⽬组成。5.protectedinternal:受保护内部访问修饰符,表⽰成员可以在同⼀程序集内和派⽣类中访问。这是protected和internal的组合,提供了更⼤的访问范围。

字段

在C#中,字段(Fields)是类中⽤于存储数据的成员,可以是公共的(public)、私有的(private)或受保护的(protected)。字段存储对象的状态和数据,并且可以通过类的实例进⾏访问和操作。

属性      

在C#中,属性(Properties)提供了对私有字段的访问,并允许控制对字段的访问⽅式。属性可以⽤于获取(get)和设置(set)字段的值,并且可以在访问时执⾏其他逻辑。

public static void ClassName
{private int age;public int Age{get{return age;}set{age = value;}}
}

字段和属性的区别

字段

字段可以直接访问,不受限制,无法对字段读写进行额外控制。

字段是类的成员变量。

字段只提供了简单的数据存储功能。

属性

属性通过访问器来访问(get和set),可以自定义读写逻辑。

属性可以封装字段。

属性的功能更加灵活。

构造函数

是一种特殊的方法。

构造函数可以有多个重载,每个重载可以接受不同类型和数量的参数,以满⾜不同的初始化需求。

使用构造函数的时候必须实例化(new)关键字。

构造函数在对象创建的过程中⾃动调⽤,⽤于执⾏初始化操作。可以在构造函数中设置字段的初始值、执⾏其他必要的操作,或者调⽤其他⽅法来完成初始化过程。

事件

是⼀种⽤于实现发布者-订阅者模式的机制,⽤于在对象之间传递消息和通知。事件允许⼀个对象(称为发布者)触发事件,并允许其他对象(称为订阅者)注册为事件的观察者,以便在事件发⽣时接收通知并执⾏相应的操作。

 public event EventHandler Work;public void onWork(){ Work.Invoke(this, EventArgs.Empty); }//事件触发static void Main(string[] args) { //实例化Program p = new Program();//订阅事件p.Work += Program.Working;//触发事件p.onWork();}//事件public static void Working(object sender, EventArgs e){Console.WriteLine("正在工作");}

索引器

 private int[] arr = new int[10];public int this[int index]{ get { return arr[index]; } set { arr[index] = value; }}static void Main(string[] args) { Program p = new Program();p[0] = 10;p[1] = 20;Console.WriteLine(p[0]);Console.WriteLine(p[1]);}

面向对象三大特性

封装

封装的意义在于保护或者防⽌代码(数据)被我们⽆意中破坏。

适当的封装可以让程式码更容易理解与维护,进⽽增强数据的安全性和简化程序的编写⼯作。

封装既可以封装成员变量,⼜可以封装成员⽅法(或属性)

static void Main() { Console.WriteLine("Hello, World!");Console.WriteLine("Hello, World!1");Console.WriteLine("Hello, World!2");Console.WriteLine("Hello, World!3");}

继承

继承是⾯向对象程序设计中最重要的概念之⼀。

继承→根据⼀个现有类来定义新类

好处:使得创建和维护应⽤程序变得更容易;

也有利于重⽤代码和节省开发时间。当创建⼀个新类时,如果这个类的某些成员和⼀个现有类相同。程序员不需要完全重新编写新的数据成员和成员函数,只需要创建⼀个新的类,继承这个现有类即可。这个已有的类被称为的基类,这个新的类被称为派⽣类。

class program:(继承的类)

多态

多态是同⼀个⾏为具有多个不同表现形式或形态的能⼒。

通俗地说:同⼀操作作⽤于不同的对象,产⽣不同的结果。

在C#中,每个类型都是多态的,因为包括⽤户定义类型在内的所有类型都继承⾃Object。

using System;class Program 
{public interface IWorker
{void Work();
}public class Engineer : IWorker
{public void Work(){Console.WriteLine("Engineer is working on a project.");}
}public class Designer : IWorker
{public void Work(){Console.WriteLine("Designer is working on a design.");}
}public class Manager
{private IWorker worker;public Manager(IWorker worker){this.worker = worker;}public void AssignWork(){worker.Work();}
}public static void Main(string[] args){Engineer engineer = new Engineer();Designer designer = new Designer();Manager manager = new Manager(engineer);manager.AssignWork();  // 输出: Engineer is working on a project.manager = new Manager(designer);manager.AssignWork();  // 输出: Designer is working on a design.}
}

 在C#中,多态性是指同一个接口可以被不同的类实现,从而允许这些类以不同的方式响应相同的消息。多态性通常通过继承和接口来实现。下面是一个简单的例子,展示了如何使用继承和接口来实现多态性。

首先,定义一个接口`IWorker`:
public interface IWorker
{
    void Work();
}
 

然后,定义两个类`Engineer`和`Designer`,它们都实现了`IWorker`接口:


public class Engineer : IWorker
{
    public void Work()
    {
        Console.WriteLine("Engineer is working on a project.");
    }
}

public class Designer : IWorker
{
    public void Work()
    {
        Console.WriteLine("Designer is working on a design.");
    }
}
 

接下来,定义一个`Manager`类,它包含一个`IWorker`类型的成员变量,并使用多态性来调用`Work`方法:


public class Manager
{
    private IWorker worker;

    public Manager(IWorker worker)
    {
        this.worker = worker;
    }

    public void AssignWork()
    {
        worker.Work();
    }
}
 

最后,在`Main`方法中演示多态性的使用:


public class Program
{
    public static void Main(string[] args)
    {
        Engineer engineer = new Engineer();
        Designer designer = new Designer();

        Manager manager = new Manager(engineer);
        manager.AssignWork();  // 输出: Engineer is working on a project.

        manager = new Manager(designer);
        manager.AssignWork();  // 输出: Designer is working on a design.
    }
}

在这个例子中,`Manager`类通过`IWorker`接口与`Engineer`和`Designer`类进行交互,而不需要知道具体是哪种类型的对象。这就是多态性的体现,它允许`Manager`类以统一的方式处理不同类型的`IWorker`对象。

多态性分为两种:

静态多态

动态多态

静态多态

根据传递的参数、返回类型等决定执⾏的操作⽅法重载——同⼀个范围内对相同的函数名有多个定义。参数列表个数或者类型不同。

动态多态

直到系统运⾏时,才决定实现何种操作通过抽象⽅法和虚⽅法实现的。

虚拟

当一个方法使用virtual修饰的时候,代表是虚方法,可以override重写子类。

注意:相同的方法以及参数列表

密封

当对⼀个类应⽤sealed修饰符时,此修饰符会阻⽌其他类从该类继承。

new:继承类中的⼀个⽅法“隐藏”基类中同名的⽅法。它会取代原⽅法,⽽不是覆盖。

抽象类

关键字abstract创建抽象类。当⼀个派⽣类继承⾃该抽象类时,必须实现该抽象类中的抽象⽅法。抽象类的⼀些规则:

不能直接创建⼀个抽象类的实例。

不能在⼀个抽象类外部声明⼀个抽象⽅法。

抽象类不能被声明为sealed。

抽象类可以包含抽象⽅法,抽象⽅法可被派⽣类实现。

抽象类可以定义普通⽅法、虚⽅法,并可以有实现。

 在C#中,抽象类是一种特殊的类,它不能被实例化,只能被继承。抽象类可以包含抽象方法和非抽象方法。抽象方法是一种没有实现的方法,必须在派生类中实现。下面是一个简单的例子,展示了如何使用抽象类。

using System;public abstract class Animal
{public abstract void MakeSound();public void Sleep(){Console.WriteLine("The animal is sleeping.");}
}public class Dog : Animal
{public override void MakeSound(){Console.WriteLine("The dog barks.");}
}public class Cat : Animal
{public override void MakeSound(){Console.WriteLine("The cat meows.");}
}public class Program
{public static void Main(string[] args){Animal myDog = new Dog();myDog.MakeSound();  // 输出: The dog barks.myDog.Sleep();      // 输出: The animal is sleeping.Animal myCat = new Cat();myCat.MakeSound();  // 输出: The cat meows.myCat.Sleep();      // 输出: The animal is sleeping.}
}

Animal类是一个抽象类,它包含一个抽象方法MakeSound和一个非抽象方法SleepDogCat类继承自Animal类,并实现了MakeSound方法。通过创建Animal类型的引用,可以调用MakeSound方法,而不需要知道具体是哪种类型的对象。这就是抽象类的使用,它允许我们以统一的方式处理不同类型的对象。

接口

接⼝本⾝并不实现任何功能,它只是和声明实现该接⼜的对象订⽴⼀个必须实现哪些⾏为的契约。

关于接口的定义请看多态的代码定义即可。

public interface inter
{void work();   
}

数组

简单数组

在声明数组时,应先定义数组中元素的类型,其后是⼀对空⽅括号和⼀个变量名。例如,下⾯声明了⼀个包含整型元素的数组∶

int[] myArray;

数组初始化

声明了数组后,就必须为数组分配内存,以保存数组的所有元素。数组是引⽤类型,所以必须给它分配堆上的内存。 

int[] myArray = new int[5];string[] stringArray = {1,2,3,4,5};//不同数组初始化

访问数组

在声明和初始化数组后,就可以使⽤索引器访问其中的元素了。数组只⽀持有整型参数的索引器,引用的用get、set。

int[] myArray = {1,2,3,4,5};int a = myArray[0]; //--1int b = myArray[3]; //--4//如果是复制过来的数组不知道元素个数,可以使用for/foreach遍历;
for(int i=0;i<myArray.Length;i++)
{Console.WriteLine(myArray[i]);
}foreach(int var in myArray)
{Console.WriteLine(var);
}

多维数据

多维数组⽤两个或多个整数来索引。

在C#中声明这个⼆维数组,需要在⽅括号中加上⼀个逗号。数组在初始化时应指定每⼀维的⼤⼩(也称为阶)。接着,就可以使⽤两个整数作为索引器来访问数组中的元素∶

int[,] one = new int[3,3];one[0,0] = 1;
//以此类推int[,] two = {{1,2,3},{4,5,6},{7,8,9}};//三维数组
int[,,] three = {{{1,2},{3,4}},{{5,6},{7,8}},{{9,0},{11,12}}};
Console.WriteLine(three[1,1,1]); //8
Console.WriteLine(three[0,1,1]); //4

锯齿数据

如果说一/二/三维数字式1*1/2*2/3*3,那么锯齿数据就是不规则的。

 int[][] ints = new int[3][];ints[0] = new int[2] { 1, 2 };ints[1] = new int[3] { 3,4,5 };ints[2] = new int[5] { 6,7,8,9,0 };for(int i = 0; i < ints.Length; i++){for(int j = 0; j < ints[i].Length; j++){Console.WriteLine($"i:{i},j:{j},value:{ints[i][j]}");}}

复制数组

    int[] intCopyArrayOne = {1,2,3};int[] intCopyArrayTwo = (int[])intCopyArrayOne.Clone();intCopyArrayTwo[0] = 100;Console.WriteLine(intCopyArrayOne[0]); //输出1Console.WriteLine(intCopyArrayTwo[0]); //输出100Console.WriteLine(intCopyArrayOne[1]); //输出2Console.WriteLine(intCopyArrayTwo[1]); //输出2Console.WriteLine(intCopyArrayOne[2]); //输出3Console.WriteLine(intCopyArrayTwo[2]); //输出3Console.WriteLine(intCopyArrayOne.Length); //输出3Console.WriteLine(intCopyArrayTwo.Length); //输出3Console.WriteLine(intCopyArrayOne == intCopyArrayTwo); //输出False

排序

string[] names = { "dog", "cat", "pig", "cow" };Array.Sort(names);foreach (string name in names) {Console.WriteLine(name);}

集合

List是与数组相当的集合类。.NETFramework为动态列表提供了泛型类List。这个类实现了IList、ICollection、Emumerable、List<ICollection和IEnumerable接⼝。

List<int> intList = new List<int>(){1,2,3};List<string> stringList = new List<string>(){"One","Two","Three"};//添加元素有Add
intList.Add(4);stringList.Add("Four");//Add只能单个添加,AddRange()批量添加;intList.AddRange(new int[]{4,5,6});stringList.AddRange(new string[]{"Four","Five","Sex"});//添加元素InsertstringList.Insert(3,"aaa");//访问元素 可以根据索引或者循环string num = stringList[3];for(int i=0;i<intList.Length;i++)
{Console.WriteLine(intList[i])
}//删除元素
//RemoveAt 根据索引删除
stringList.RemoveAt(5);
//Remove 删除指定元素
stringList.Remove("three");
//RemoveRange 批量删除
stringList.RemoveRange(3,3);//查找元素
int strListIndex = stringList.IndexOf("Two");
Console.WriteLine(strListIndex);Console.WriteLine(intList.Find(x => x>5));//查找大于5Console.WriteLine(intList.FindIndex(x => x>5));//查找大于5索引Console.WriteLine(intList.FindAll(x => x>5));//查询所有大于5//排序--Sort 快速排序List<int> intList2 = new List<int>(){3,5,0};intList2.Sort();
foreach(var item in intList2)
{Console.WriteLine(item);
}//②
List<Person> pList = new List<Person>(){new Person("Aa","Aa"),new Person("Zz","Zz"),};pList.Sort();foreach(var item in pList)
{Console.WriteLine(item);
}

集合初始值设定项只能在声明集合时使⽤。AddRange()⽅法则可以在初始化集合后调⽤。如果在创建集合后动态获取数据,就需要调⽤AddRange0。

泛型

在C#中,泛型是⼀种参数化类型的机制,它允许在定义类、结构、接⼜和⽅法时使⽤类型参数。使⽤泛型可以创建可以在多个数据类型上⼯作的通⽤代码,⽽不需要针对每种具体类型编写重复的代码。泛型的主要优势是提⾼了代码的可重⽤性、类型安全性和性能。通过使⽤泛型,可以编写更加灵活和通⽤的代码,同时在编译时进⾏类型检查,避免在运⾏时出现类型错误。

using System;/// <summary>
/// Box<T>是一个泛型类,它使用类型参数T来表示内容类型。
/// SetContent和GetContent方法都是泛型方法,它们接受和返回类型为T的参数。
/// 在Main方法中,创建了Box<int>和Box<string>的实例,并分别设置了整数和字符串内容。
/// 通过使用泛型,我们可以在不牺牲类型安全的情况下,创建可以处理不同数据类型的通用组件。
/// </summary>
/// <typeparam name="T"></typeparam>
public class Box<T>
{private T content;public void SetContent(T content){this.content = content;}public T GetContent(){return content;}
}
public class Program
{public static void Main(string[] args){Box<int> intBox = new Box<int>();intBox.SetContent(10);Console.WriteLine(intBox.GetContent());  // 输出: 10Box<string> stringBox = new Box<string>();stringBox.SetContent("Hello, World!");Console.WriteLine(stringBox.GetContent());  // 输出: Hello, World!}
}

委托

在C#中,委托(Delegate)是⼀种类型,它允许您将⽅法作为参数传递,并在需要时调⽤该⽅法。委托可以⽤于声明⽅法的签名,并且可以创建对符合该签名的任何⽅法的引⽤。委托可⽤于实现事件和回调机制,使得代码更加灵活和可扩展。它提供了⼀种在运⾏时动态决定要调⽤的⽅法的⽅式,这对于处理异步操作、事件处理程序和回调函数⾮常有⽤。

using System;/// <summary>
/// Action是一个委托,它定义了一个没有参数且没有返回值的方法签名。
/// SayHello方法与Action委托的签名兼容,因此我们可以创建一个Action委托的实例,
/// 并将SayHello方法赋值给它。然后,我们可以通过调用action来执行SayHello方法。
/// </summary>public delegate void Action();public class Program{public static void Main(string[] args){Action action = new Action(SayHello);action();  // 输出: Hello, World!void SayHello(){Console.WriteLine("Hello, World!");}}}/// <summary>
/// 在这个例子中,ActionWithParam是一个委托,它定义了一个接受一个整数参数且没有返回值的方法签名。
/// PrintNumber方法与ActionWithParam委托的签名兼容,
/// 因此我们可以创建一个ActionWithParam委托的实例,并将PrintNumber方法赋值给它。
/// 然后,我们可以通过调用action并传递参数来执行PrintNumber方法。
/// </summary>
/// <param name="param"></param>
public delegate void ActionWithParam(int param);public class Program
{public static void Main(string[] args){ActionWithParam action = new ActionWithParam(PrintNumber);action(42);  // 输出: 42void PrintNumber(int number)
{Console.WriteLine(number);
}}
}

 

lambda/Linq

Lambda表达式是一种匿名函数,可以用于表示简单的函数逻辑。LINQ(Language Integrated Query)是一种查询语言,

1.基本语法:Lambda表达式由参数列表、箭头符号和表达式组成。

2.表达式体和语句体:允许在Lambda表达式中编写多个语句。

3.引⽤外部变量:Lambda表达式可以引⽤外部作⽤域中的变量。即闭包。

4.异步⽀持:async和await关键字,使得异步编程变得更加容易。Lambda表达式可以与异步⽅法⼀起使⽤,从⽽提供异步操作的简洁语法。

Lambda表达式的应⽤⾮常⼴泛:

1.LINQ查询:Lambda表达式可以作为LINQ查询的条件和投影函数,简化了对集合的筛选、排序和转换操作。

var result =collection.Where(x=>x>5).0rderBy(x => x).Select(x =>x);

2.委托和事件处理:Lambda表达式可以⽤于创建委托实例,或者作为事件处理程序。

Action<int>action=x=>Console.WriteLine(x);
button.Click +=(sender,e)=> Console.WriteLine("Button clicked");

3.并⾏编程:通过Parallel类和TaskParallelLibrary(TPL)等并⾏编程框架,Lambda表达式可以⽤于创建并⾏任务和线程。

Parallel.For(0,10,i=>Console.WriteLine(i));Task.Run(()=>{/* 任务代码 */});

4.表达式树:Lambda表达式可以被编译为表达式树,使得我们能够在运⾏时分析和操作代码。

using System;/// <summary>
/// 创建了一个Person对象的列表。
///使用Lambda表达式和LINQ查询来筛选年龄大于30的人。
///Lambda表达式p => p.Age > 30定义了一个匿名函数,
///它接受一个Person对象并返回一个布尔值,表示该对象的年龄是否大于30。
///LINQ查询from p in people where p.Age > 30 select p使用Where子句来筛选满足条件的对象,
///并使用Select子句来选择结果对象。最后,我们使用foreach循环来输出结果。
/// </summary>
public class Person
{public string Name { get; set; }public int Age { get; set; }
}public class Program
{public static void Main(string[] args){List<Person> people = new List<Person>{new Person { Name = "Alice", Age = 30 },new Person { Name = "Bob", Age = 25 },new Person { Name = "Charlie", Age = 35 }};// 使用Lambda表达式筛选年龄大于30的人var adults = people.Where(p => p.Age > 30);// 使用LINQ查询年龄大于30的人var adultsLinq = from p in peoplewhere p.Age > 30select p;// 输出结果foreach (var person in adults){Console.WriteLine($"{person.Name} is an adult.");}foreach (var person in adultsLinq){Console.WriteLine($"{person.Name} is an adult.");}}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/386308.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ubuntu20.04安装nginx,mysql8,php7.4详细教程,包成功

目录 1.更新索引 2.安装 Nginx 1.安装 Nginx&#xff1a; 2.启动 Nginx 服务并设置为开机自启&#xff1a; 3.开放防火墙的 80 端口&#xff1a; 4.检查 Nginx 是否正常运行&#xff1a; 3.安装 MySQL 8.0 1.首先&#xff0c;安装 MySQL 的仓库&#xff1a; 安装过程中你会看…

RewardBench:Evaluating Reward Models for Language Modeling

Leaderboard&#xff1a; https://hf.co/spaces/allenai/reward-bench Code&#xff1a; https://github.com/allenai/reward-bench Dataset&#xff1a; https://hf.co/datasets/allenai/reward-bench 在人类偏好的强化学习&#xff08;RLHF&#xff09;过程中&#xff0c;奖励…

【Vulnhub系列】Vulnhub_Seattle_003靶场渗透(原创)

【Vulnhub系列靶场】Vulnhub_Seattle_003靶场渗透 原文转载已经过授权 原文链接&#xff1a;Lusen的小窝 - 学无止尽&#xff0c;不进则退 (lusensec.github.io) 一、环境准备 1、从百度网盘下载对应靶机的.ova镜像 2、在VM中选择【打开】该.ova 3、选择存储路径&#xff0…

【AI大模型】-- 应用部署

一、GPU价格参考 有些在京东就能买到&#xff1a;https://item.jd.com/10065826100148.html美国商务部限制 GPU 对华出口的算力不超过 4800 TOPS 和带宽不超过 600 GB/s&#xff0c;导致最强的 H100 和 A100 禁售。英伟达随后推出针对中国市场的 A800 和 H800。 H100 与 A100&…

CATIA V5R21安装包下载及图文安装教程

大家好&#xff0c;今天给大家分享下catia安装教程 注意安装前请退出杀毒软件&#xff0c;防止误报影响安装进程 下载链接&#xff1a;百度网盘 请输入提取码 提取码&#xff1a;ypc6 01 在电脑D盘新建文件夹命名为CATIA,将下载的软件压缩包放置在该文件夹。 鼠标右击【C…

淘宝测试环境治理实践

去年之前&#xff0c;阿里巴巴的淘天集团测试环境是以领域方式运作&#xff1a;不局限测试环境治理本身&#xff0c;从测试模式方法论及用好测试环境思路引领集团测试环境治理。领域运作最难的是“统一思想”。业务进一步细分调整后&#xff0c;测试环境治理策略理应由业务方自…

【MetaGPT系列】【MetaGPT完全实践宝典——多智能体实践】

目录 前言一、智能体1-1、Agent概述1-2、Agent与ChatGPT的区别 二、多智能体框架MetaGPT2-1、安装&配置2-2、使用已有的Agent&#xff08;ProductManager&#xff09;2-3、多智能体系统介绍2-4、多智能体案例分析2-4-1、构建智能体团队2-4-2、动作/行为 定义2-4-3、角色/智…

若能重回白宫,特朗普称将把比特币列为美国战略储备资产!

KlipC报道&#xff1a;当地时间7月29日&#xff0c;美国前总统特朗普参加比特币2024大会&#xff0c;并在会上宣布称&#xff0c;如果重返白宫&#xff0c;他将把比特币列为美国战略储备资产。讲话期间&#xff0c;比特币价格一度上涨到6.9万美元大关。 特朗普表示&#xff1a…

Photos框架 - 自定义媒体选择器(UI预览)

引言 在前面的博客中我们已经介绍了使用媒体资源数据的获取&#xff0c;以及自定义的媒体资源选择列表页。在一个功能完整的媒体选择器中&#xff0c;预览自然是必不可少的&#xff0c;本篇博客我们就来实现一个资源的预览功能&#xff0c;并且实现列表和预览的数据联动效果。…

前端基于 axios 实现批量任务调度管理器 demo

一、背景介绍 这是一个基于 axios 实现的批量任务调度管理器的 demo。它使用了axios、promise 等多种技术和原理来实现批量处理多个异步请求&#xff0c;并确保所有请求都能正确处理并报告其状态。 假设有一个场景&#xff1a;有一个任务列表&#xff0c;有单个任务的处理功能…

PyQt ERROR:ModuleNotFoundError: No module named ‘matplotlib‘

Solution:打开cmd输入指令下载malplotlib pip install matplotlib

2024-07-27 Unity Excel —— 使用 EPPlus 插件读取 Excel 文件

文章目录 1 前言2 项目地址3 使用方法3.1 写入 Excel3.2 读取 Excel3.3 读写 csv 文件 4 ExcelSheet 代码 1 前言 ​ 前几日&#xff0c;一直被如何在 Unity 中读取 Excel 的问题给困扰&#xff0c;网上搜索相关教程相对古老&#xff08;4、5 年以前了&#xff09;。之前想用 …

力扣高频SQL 50题(基础版)第二十五题

文章目录 力扣高频SQL 50题&#xff08;基础版&#xff09;第二十五题619.只出现一次的最大数字题目说明实现过程准备数据实现方式结果截图 力扣高频SQL 50题&#xff08;基础版&#xff09;第二十五题 619.只出现一次的最大数字 题目说明 MyNumbers 表&#xff1a; ------…

wpf中轮询显示图片

本文的需求是&#xff0c;在一个文件夹中&#xff0c;放一堆图片的集合&#xff0c;然后在wpf程序中&#xff0c;按照定时的方式&#xff0c;循序显示照片。 全部代码 1.声明一个PictureInfo类 namespace WpfApp1 {public class PictureInfo{public string? FileName { get; …

【计算机网络】三次握手、四次挥手

问&#xff1a;三次握手 四次挥手 TCP 连接过程是 3 次握手&#xff0c;终止过程是 4 次挥手 3次握手 第一步&#xff1a;客户端向服务器发送一个带有 SYN&#xff08;同步&#xff09;标志的包&#xff0c;指示客户端要建立连接。 第二步&#xff1a;服务器收到客户端的请求…

Java设计模式—单例模式(Singleton Pattern)

目录 一、定义 二、应用场景 三、具体实现 示例一 示例二 四、懒汉与饿汉 饿汉模式 懒汉模式 五、总结 六、说明 一、定义 二、应用场景 ‌单例模式的应用场景主要包括以下几个方面&#xff1a; ‌日志系统&#xff1a;在应用程序中&#xff0c;通常只需要一个日…

Spring之Spring Bean的生命周期

Spring Bean的生命周期 通过BeanDefinition获取bean的定义信息调用构造函数实例化beanBean的依赖注入处理Aware接口&#xff08;BeanNameAware、BeanFactoryAware、ApplicationContextAware&#xff09;Bean的后置处理器BeanPostProcessor-前置初始化方法&#xff08;Initiali…

关于@JsonSerialize序列化与@JsonDeserialize反序列化注解的使用(密码加密与解密举例)

注&#xff1a;另一种方式参考 关于TableField中TypeHandler属性&#xff0c;自定义的类型处理器的使用&#xff08;密码加密与解密举例&#xff09;http://t.csdnimg.cn/NZy4G 1.简介 1.1 序列化与反序列化 学习注解之前&#xff0c;我们可以先了解一下什么是序列化与反序列…

115. 不同的子序列 dp入门(一)详细推导dp转移方程式

目录 1. 题目引入&#xff1a; 2. 动态规划解法 2.1 动态dp表示 2.2 动态方程推导: 2.3 具体分析 2.4 初始化 3. 代码如下 java版 c版 Python版 1. 题目引入&#xff1a; 给你两个字符串 s 和 t &#xff0c;统计并返回在 s 的 子序列 中 t 出现的个数&#xff0c;结果…

计算机基础(day1)

1.什么是内存泄漏&#xff1f;什么是内存溢出&#xff1f;二者有什么区别&#xff1f; 2.了解的操作系统有哪些&#xff1f; Windows&#xff0c;Unix&#xff0c;Linux&#xff0c;Mac 3. 什么是局域网&#xff0c;广域网&#xff1f; 4.10M 兆宽带是什么意思&#xff1f;理论…