1.静态static
static 关键字 静态类 里面的成员信息必须是静态的,是不能实例化的
在C#编程语言中,关键字static
用于声明静态成员。静态成员属于类,而不是类的实例。以下是一些关于静态成员的重要事实:
-
静态字段(静态变量):使用
static
关键字声明的字段是属于类的,而不是类的实例。静态字段在所有类的实例之间共享相同的值。 -
静态方法:使用
static
关键字声明的方法是属于类的,而不是类的实例。静态方法可以直接通过类名调用,无需创建类的实例。 -
静态属性:使用
static
关键字声明的属性是属于类的,而不是类的实例。静态属性在所有类的实例之间共享相同的值。 -
静态构造函数:使用
static
关键字声明的构造函数被称为静态构造函数。静态构造函数在类的类型被首次访问时自动调用,用于初始化静态成员。
使用静态成员的好处是可以在不创建类的实例的情况下访问它们,并且它们可以在应用程序的任何地方共享相同的值。静态成员通常用于表示应用程序范围内的一些共享数据或提供全局性的功能。
需要注意的是,静态成员不能访问非静态成员,因为非静态成员依赖于类的实例。此外,静态成员也不能被继承或重写,因为它们属于类本身而不是实例。
static void Main(string[] args)
{
Test t1 = new Test();
t1.age = 100;
// t1.id = 200; 报错 不能通过对象去访问静态数据
// 通过类去访问静态数据
Test.id = 200;
Test.Show1();
}
class Test
{
public int age;
// 静态字段,代表这个字段是被Test类所共享的一个字段,是存储在静态资源区的,可以通过类访问,但是不能通过类实例化对象去访问
public static int id;
public void Show()
{
Console.WriteLine(age);
}
// 静态方法只能使用静态数据
public static void Show1()
{
Console.WriteLine(id);
}
}
2.接口
interface 定义接口的关键字;定义接口,只有方法,没有结构体,没有其它的任何信息 定义一个接口在语义上跟定义一个抽象类完全相同,但是不允许提供接口中任何成员的实现方式,一般情况下,接口中只能包含方法,属性,索引器,事件的声明;不允许声明成员上的修饰符,即使public都不行,因为接口成员总是公有的,也不能声明虚方法,如果需要修饰符,最好让类来实现 注意:1.接口中不能有构造函数,也不能有数据字段,接口不允许运算符重载 2.接口定义中不允许声明成员的修饰符,接口都是公有的
实现接口:用接口的作用,假如某一个板块需要若干个方法,那我们就可以把这几个方法的定义放在方法里面,如果想要某个类去实现这个功能,我们就需要实现这个接口,任意一个类都可以使用这个接口;使用的前提是,必须满足接口中的方法
使用接口 : 1.通过实例化 2.使用接口声明一个对象,用两个类去实例化,这在编程中,也叫多态,因为Fly发生了变化;之前是一架飞机,最后变成了小鸟;所以他的形态时刻变化的,这种语法在C#中就叫多态
// 接口通过使用 interface 关键字来声明。下面是一个接口的例子:
public interface IMyInterface
{
void MyMethod();
string MyProperty { get; set; }
}
// 在接口中,可以声明方法(不包含具体实现)、属性(只有 getter 和/或 setter)和事件。接口的成员默认是公有的,并且不允许包含字段或常量。
// 类可以实现一个或多个接口,通过使用关键字 class 实现接口。实现接口的类必须提供接口中声明的所有成员的具体实现。例如:
public class MyClass : IMyInterface
{
public void MyMethod()
{
// 具体实现
}
public string MyProperty { get; set; }
}
接口的主要作用是定义一组约定,使得不同的类可以按照相同的方法、属性和事件进行操作,以实现代码的组织和重用。接口也可以用于实现多态性,通过接口引用可以调用实现该接口的不同类的成员。
需要注意的是,接口本身不提供任何实现代码,它只是定义了一组要求实现者必须遵守的成员。具体的实现代码在实现接口的类中编写。
3.接口继承
在C#编程语言中,接口(Interface)之间可以通过接口继承形成继承关系。这种继承关系允许一个接口从一个或多个父接口继承成员,从而在子接口中获得父接口定义的方法、属性和事件。
// 使用冒号(:`)可以让一个接口继承自另一个或多个接口。下面是一个展示接口继承的示例:
public interface IAnimal
{
void Eat();
}
public interface IFlyable
{
void Fly();
}
public interface IBird : IAnimal, IFlyable
{
void BuildNest();
}
// 在上面的示例中,接口IAnimal和IFlyable分别定义了Eat和Fly方法。接口IBird通过使用冒号(:)继承了IAnimal和IFlyable接口,同时还新增了自己的BuildNest`方法。
// 类可以实现接口继承后的接口,从而需要实现继承链中定义的所有方法。例如:
public class Sparrow : IBird
{
public void Eat()
{
// 具体实现
}
public void Fly()
{
// 具体实现
}
public void BuildNest()
{
// 具体实现
}
}
// 在上面的示例中,Sparrow类实现了IBird接口,并提供了IAnimal和IFlyable接口中定义的方法的具体实现,以及IBird接口新增的BuildNest方法。
接口继承的主要目的是为了实现代码的组织和重用。通过接口继承,可以将共同的方法、属性和事件定义在父接口中,而不同的子接口可以通过继承父接口来扩展额外的功能。类可以选择性地实现接口继承链中的接口,以满足特定的需求。
4.运算符重载
在C#编程语言中,运算符重载(Operator Overloading)是指通过自定义运算符对特定类型的操作进行重新定义。通过运算符重载,可以为用户定义的类或结构定义自己的行为,使其支持类似于内置类型的运算。
要进行运算符重载,需要在类或结构中声明运算符重载的方法,方法名称必须是以 operator
关键字开头,后跟要重载的运算符。
使用运算符重载后,可以像使用内置类型一样使用运算符来操作自定义类型的对象。
需要注意的是,运算符重载只适用于自定义类型,不能对内置类型进行运算符重载。此外,有一些运算符是不能被重载的,例如赋值运算符 =
和条件运算符 ?:
。在进行运算符重载时,需要遵循一些规则和约定,以确保代码的可读性和合理性。
static void Main(string[] args)
{
// + - * / == !=
// 函数重载就是重写某个函数,运算符重载就是把运算重写
Student s1 = new Student(18,"小张",20230831);
Student s2 = new Student(18,"小张",20230831);
Student s3 = s1;
// Console.WriteLine(s1==s2); // 不一样的原因,s1与s2的地址不同,堆栈
// Console.WriteLine(s3==s1); // 一样,是因为s1与s3是共用的一个内存地址,指向的是堆中的通过一个内存
// 使用运算符重载,当运算符比较时,默认时应用比较,而运算符重载是通过定义的方法逻辑重载
// 使用运算符重载,去比较两个堆内存中的每一个属性值
Console.WriteLine(s1 == s2);
Console.WriteLine(s3 != s2);
}
internal class Student
{
public int age;
public string name;
public long id;
public Student(int age, string name, long id)
{
this.age = age;
this.name = name;
this.id = id;
}
// operator运算符重载,公有的,静态的,有返回值,声明的运算符重载 (两个形参 调用==,左边的是第一个参数值,右边的是第二个参数值)
public static bool operator ==(Student s1,Student s2)
{
if (s1.name == s2.name && s1.age == s2.age && s1.id == s2.id)
{
return true;
}
return false;
}
public static bool operator !=(Student s2, Student s3)
{
bool result = s2 == s3;
return !result;
}
}
5.索引器
在C#编程语言中,索引器(Indexer)提供了一种访问类或结构中的元素的简便方式。通过使用索引器,可以像使用数组一样使用索引来访问类或结构中的元素,通过在类型中定义索引器,可以为类型提供集合或列表的访问方式。
要声明索引器,需要在类或结构中定义一个特殊的成员,类似于属性的语法,但使用索引器关键字 this
声明。索引器可以有一个或多个参数,用于传递索引值
使用索引器时的语法类似于访问数组元素的语法,通过在对象后方使用方括号并传入索引值,可以访问或修改对应索引的元素。
需要注意的是,索引器可以有多个参数,并且参数的类型可以是除了 ref
和 out
之外的任何类型。索引器本质上是一种特殊的属性,可以通过设置索引器的 get
和 set
访问器来自定义索引值的访问行为。使用索引器可以使自定义类或结构以类似于数组的方式访问和操作其中的元素,提供更方便和灵活的接口。
static void Main(string[] args)
{
// 当我们想要访问数组里面的某个数据的时候是通过索引来访问的,那[1]就是索引器
int[] array = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
// 这里注意:这是使用索引器,可以是通过索引其取值,也可以赋值
array[1] = 10;
Console.WriteLine(array[1]);
// 类也可以使用索引器
// 类使用索引器
Test t = new Test();
// 设置值[5]设置一个值,就是传递过去的索引index 200就是传递过的value
t[5] = 200;
// 取值
int temp = t[5];
Console.WriteLine("取到的值 " + temp);
// 通过set给数组设置值,最终还是通过对象实现的
Test t1 = new Test();
t1[0] = "A";
t1[1] = "B";
// 通过get取值
Console.WriteLine(t1[0]);
Console.WriteLine(t1[1]);
Console.WriteLine(t1[2]);
}
internal class Test
{
// 索引器的定义,通过索引器去访问某个属性的值的时候,会有一个返回值,索引器可以设置也可以获取,获取的时候要返回一个值,就是return一个值
public int this[int index]
{
get
{
Console.WriteLine(index);
return index;
}
set
{
Console.WriteLine(index);
// value 设置的时候传过来一个值,这个值就是value
Console.WriteLine(value);
}
}
string[] name = new string[10];
public string this[int index]
{
get
{
return name[index];
}
set
{
name[index] = value;
}
}
}