静态方法
特点:1.生命周期----一旦创建-->应用结束 才会结束
2.范围是全局的
3.效率高
注意 静态的东西创建多了占用内存就大了、非必要情况不要创建静态对象
静态方法调用 ,非静态方法 不能直接调用
用处
用户登录信息、系统配置信息、系统设置、SQLhelper
internal class Program
{
static void Main(string[] args)
{
print1();
Program program = new Program();
program.print2();
}
public static void print1()
{
("这是静态方法");
}
public void print2() {
("这是非静态方法");
}
}
构造方法
用处
初始化对象,或者初始化一些数据
特点:默认是一个无参数构造方法,可以多个并重载
在Visual Studio 2022 中,使用ctor快速生成 C# 构造方法
析构方法
用于在对象被垃圾回收器回收前执行清理工作。析构方法没有返回类型,也没有参数,并且其名称是固定的
作用
释放方法
谁在使用:GC垃圾回收器
垃圾回收机制
回收非托管资源:windows窗口句柄、数据库链接、GID对象、独占文件锁等等对象
析构方法的特点
-
自动调用:析构方法不是由程序员显式调用的,而是由垃圾回收器在对象不再被使用时自动调用。
-
不可继承:析构方法不能被子类继承或重写。
-
只读属性:析构方法不能访问非静态的只读字段。
-
调用限制:析构方法不能包含任何参数,不能被声明为静态,也不能声明访问修饰符(如public, private等)。
-
执行顺序:析构方法在对象的生命周期结束时执行,但具体的执行时机取决于垃圾回收器的算法和运行时环境。
class ResourceHolder
{
// 假设这是一个需要清理的资源
public IntPtr resource;
public ResourceHolder()
{
// 模拟资源分配
resource = (1024);
}
~ResourceHolder()//~ResourceHolder() 在C#中表示 ResourceHolder 类的析构函数
{
// 清理资源
(resource);
}
}
c#中的引用类型
int[] arr = { 1, 2, 3, 4, 5 };
int[] arr2 = arr;
arr[0] = 11;
(arr2[0]);
当改变arr中的值时,同时还会改变arr2的值
原因
在C#中,数组是一种对象类型,存储在堆上。当您创建一个数组并将其赋值给另一个数组变量时,实际上赋值的是引用,而不是数组的内容。这意味着两个变量都指向内存中的同一个数组对象。
执行这段代码后,arr和arr2都指向同一个数组对象,包含元素1, 2, 3, 4, 5。因此,对arr2所做的任何修改都会反映在arr上,反之亦然。
如果您修改arr2中的元素,arr中的相应元素也会改变,因为它们指向同一个数组。
如果您重新分配arr2,使其指向一个新的数组对象,arr将不会受到影响,仍然指向原始数组。
虚方法
虚方法(Virtual Methods)是面向对象编程中的一个概念,它允许在基类中定义一个方法,然后在派生类中重写(Override)这个方法以提供特定的实现。以下是虚方法的一些关键特性:
-
定义:在基类中使用
virtual
关键字声明的方法称为虚方法。这表明该方法可以在派生类中被重写。 -
目的:虚方法的目的是允许派生类改变或扩展基类的行为,这是实现多态性的一种方式。
-
重写:在派生类中,使用
override
关键字来重写基类中的虚方法。 -
调用:虚方法可以通过基类类型的引用或实例调用。实际执行的方法取决于对象的实际类型,这是多态性的表现。
-
访问修饰符:虚方法可以与任何访问修饰符一起使用,如
public
、protected
、internal
等。 -
抽象类:虚方法可以在非抽象类中定义,但在抽象类中,虚方法可以被声明为抽象方法(使用
abstract
关键字),这意味着派生类必须提供具体实现。 -
非虚方法:如果基类中的方法没有使用
virtual
关键字声明,那么它是一个非虚方法。在这种情况下,即使在派生类中声明了具有相同名称和签名的方法,也不会被视为重写,而是隐藏了基类中的方法。 -
新关键字:在C#中,可以使用
new
关键字在派生类中隐藏基类的方法,即使基类中的方法不是虚方法。
internal class VirtualMethed
{
public virtual void print()
{
("这个是VirtualMethed");
}
}
class VirtualMethedChild : VirtualMethed
{
public override void print()
{
("这个是VirtualMethedChild");
}
}
static void Main(string[] args)
{
VirtualMethed virtualMethed=new VirtualMethedChild();
();
}
打印结果为:这个是VirtualMethedChild
抽象方法
抽象方法是在抽象类中声明的方法,它没有具体的实现,只是定义了方法的签名和可能的访问修饰符。抽象方法的目的是强制派生类提供这些方法的具体实现。
以下是抽象方法的一些关键特性:
-
声明:抽象方法使用
abstract
关键字在抽象类中声明。 -
无实现:抽象方法没有方法体,因此它们不包含执行的代码。
-
派生类实现:包含抽象方法的类的派生类必须重写(override)这些抽象方法,提供具体的实现。
-
强制实现:如果一个类包含抽象方法,那么它必须是抽象类,这意味着它不能被实例化。
-
访问修饰符:抽象方法可以有访问修饰符,如
public
、protected
等,这决定了派生类如何访问和重写这些方法。 -
抽象类:一个类如果包含抽象方法或抽象属性,它必须被声明为抽象类,使用
abstract
关键字。 -
接口和抽象类:接口也可以包含抽象方法,但自C# 8.0起,接口可以包含默认实现的方法,这与抽象类类似。
-
目的:抽象方法用于定义一个类的基本行为,这些行为在不同的派生类中可能有不同的实现方式。
抽象类(Abstract Classes)和接口(Interfaces)都是面向对象编程中用来实现抽象化和多态性的工具,但它们之间存在一些关键的区别:
-
定义方式:
-
抽象类使用
abstract
关键字定义,可以包含抽象方法和具体方法。 -
接口使用
interface
关键字定义,只包含没有实现的方法、属性、索引器、事件的签名。
-
-
构造和析构:
-
抽象类可以有构造函数和析构函数。
-
接口不能有构造函数或析构函数。
-
-
成员种类:
-
抽象类可以包含字段、属性(包括自动实现的属性)、方法(包括抽象和非抽象方法)、索引器、事件等。
-
接口只能包含没有实现的方法、属性、索引器和事件的签名。
-
-
实现方式:
-
一个类可以实现多个接口,但不能继承多个抽象类(多重继承)。
-
抽象类可以被具体类继承,而接口可以被类实现。
-
-
访问修饰符:
-
抽象类中的成员可以有访问修饰符,如
public
、protected
、private
等。 -
接口中的成员默认都是
public
,不能使用其他访问修饰符。
-
-
继承和实现:
-
抽象类可以继承另一个抽象类或具体类,并且可以被子类继承。
-
接口可以继承另一个接口,并且可以被类实现。
-
-
抽象方法的实现:
-
抽象类中的抽象方法必须在非抽象子类中实现。
-
接口中的所有方法都是抽象的,必须在实现接口的类中提供实现。
-
-
默认实现:
-
抽象类可以为方法提供默认实现,子类可以选择覆盖或使用默认实现。
-
从C# 8.0开始,接口也可以提供方法的默认实现,允许在接口中提供方法的实现代码,实现接口的类可以选择覆盖或使用默认实现。
-
扩展方法
是C#中的一种特殊类型的静态方法,它们允许你为现有类型“添加”新的方法,而无需修改原始类的源代码或使用继承。扩展方法实际上是定义在静态类中的静态方法,但它们可以像实例方法一样被调用。
以下是扩展方法的一些关键特性:
-
定义:扩展方法必须定义在静态类中。
-
语法:扩展方法的第一个参数使用
this
关键字标记,指定了扩展方法所扩展的类型。 -
调用:扩展方法可以像实例方法一样被调用,调用者不需要使用类名或创建类的实例。
-
发现:编译器会在编译时查找扩展方法,如果找到,它们就像普通实例方法一样可用。
-
重载:扩展方法可以被重载,就像普通方法一样。
-
继承:扩展方法不会继承给派生类,除非派生类也是扩展方法的一部分。
-
参数:除了
this
参数外,扩展方法可以有其他参数,这些参数的使用与普通方法相同。 -
返回类型:扩展方法可以有任意的返回类型。
一般扩展方法的使用
internal class Program
{
static void Main(string[] args)
{
string myString = "Hello, World!";
// 调用扩展方法,就像调用string的实例方法一样
int charCount = ();
("Character count: " + charCount);
}
// 静态类定义扩展方法
}
public static class StringExtensions
{
// 扩展方法,扩展了string类型
public static int CountChars(this string str)
{
return ; // 简单的示例,实际上string已经有Length属性
}
}
实现接口的类型定义扩展方法。
public interface Person
{
int add(int x, int y);
}
public static class PersonExtend
{
public static int Add(this Person person,int x,int y)
{
return x + y;
}
public static int Sub(this Person person, int x, int y)
{
return x -y;
}
}
internal class PersonImplementation : Person
{
public int add(int x, int y)
{
return x+ y;
}
}
static void Main(string[] args)
{
int a = 3;
int b = 3;
PersonImplementation personImplementation = new PersonImplementation();
int x = (a, b);
int y = (a, b);
(x);
(y);
}