AndreaDO

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

统计

C#的知识点1

C#基础知识

C#的接口是什么?如何编写好的接口?

C#的接口

在C#中,接口是一种抽象类型,它定义了一组成员(方法、属性、事件等)的规范,但没有实现代码。类或结构体可以实现一个或多个接口,以表明它们提供了特定的功能。接口使得多态编程变得容易,允许通过接口引用来引用实现该接口的不同类的实例,实现运行时多态性。

C#接口声明

接口使用interface关键字来声明。接口成员的声明与类成员的声明类似,但接口成员不能有访问修饰符(public、protected、internal、private等),因为接口中的方法都需要由外面接口实现去实现方法体,那么其修饰符必然是public。接口中只能包含方法、属性、事件和索引的组合。

interface IShape
{
    void Draw();
    double GetArea();
}

C#接口的实现

类或结构体可以通过使用冒号(:)符号后跟要实现的接口列表来实现一个或多个接口。

class Circle : IShape
{
    private double radius;

    public Circle(double radius)
    {
        this.radius = radius;
    }

    public void Draw()
    {
        // 绘制圆形
    }

    public double GetArea()
    {
        return Math.PI * radius * radius;
    }
}

C#的is运算符是什么?as运算符是什么?

is 运算符和 as 运算符都是用于类型检查的运算符,但它们的行为有所不同。

C#中的 is 运算符和 as 运算符

is 运算符和 as 运算符都是用于类型检查的运算符,但它们在功能和用法上有所不同。

is 运算符

is 运算符用于检查一个对象是否兼容于指定的类型。如果兼容,则返回 true;否则,返回 false。兼容性是指该对象可以转换为指定的类型而不抛出异常。

例如,以下代码检查变量 obj 是否是 MyClass 类型或其子类:

object obj = new MyClass();

if (obj is MyClass) {
  Console.WriteLine("obj 是 MyClass 类型或其子类");
}

输出:

obj 是 MyClass 类型或其子类

is 运算符不会执行实际的类型转换,它只会检查类型兼容性。因此,它不会抛出异常。此外,如果对象引用为 null,则 is 运算符总是返回 false

as 运算符

as 运算符用于将一个对象转换为指定的类型。如果转换成功,则返回转换后的对象;否则,返回 null

例如,以下代码将变量 obj 转换为 MyClass 类型:

object obj = new MyClass();

MyClass myClass = obj as MyClass;

if (myClass != null) {
  Console.WriteLine("myClass 是 MyClass 类型");
}

输出:

myClassMyClass 类型

如果 obj 不是 MyClass 类型或其子类,则 as 运算符将返回 null

as 运算符会执行实际的类型转换,因此它可能会抛出异常。例如,以下代码将字符串 "123" 转换为 int 类型:

string str = "123";

int i = str as int;

if (i != null) {
  Console.WriteLine("i 的值是:" + i);
}

输出:

i 的值是:123

如果 str 不是有效的数字字符串,则 as 运算符将抛出 FormatException 异常。

总结

以下是 is 运算符和 as 运算符的总结:

运算符 功能 用法 返回值
is 检查类型兼容性 obj is MyType truefalse
as 转换类型 obj as MyType 转换后的对象或 null

一般来说,建议使用 is 运算符来检查类型兼容性,使用 as 运算符来执行实际的类型转换。

C#的Object类

Object 类是 C# 中所有类型(包括值类型和引用类型)的基类。这意味着所有类型都从 Object 类派生,并继承了它的成员。

Object 类定义了一些基本的方法和属性,这些方法和属性对于所有类型都是通用的。例如:

  • Equals 方法:用于比较两个对象的相等性。
  • ToString 方法:用于将对象转换为字符串表示形式。
  • GetHashCode 方法:用于获取对象的哈希码。
  • GetType 方法:用于获取对象的类型信息。

此外,Object 类还定义了一些静态方法,例如 ReferenceEquals 方法,用于比较两个对象的引用是否相等。

Object类的作用

Object 类在 C# 中扮演着重要的角色,它具有以下作用:

  • 提供了所有类型之间共享的基础功能。
  • 使得不同类型的对象之间能够进行交互。
  • 支持类型转换和类型检查。

Object类的常见用法

Object 类在 C# 中的常见用法包括:

  • 将对象存储在集合中。
  • 将对象作为参数传递给方法。
  • 从基类向上转型对象。

C#中readonly和const区别

C# 中的 readonlyconst 区别

readonlyconst 都是 C# 中用于声明常量的关键字,但它们在功能和用法上有所不同。

const 关键字

const 关键字用于声明编译时常量。编译时常量是指在编译期间就已经确定值且不能更改的常量。

const 常量必须在声明时初始化,并且只能使用字面量或其他编译时常量作为初始化值。例如,以下代码声明了一个名为 PI 的编译时常量,其值为圆周率:

const double PI = 3.14159265358979323846;

编译时常量具有以下特点:

  • 值在编译期间就已经确定,不能在运行时更改。
  • 具有较高的性能,因为编译器可以直接将常量值替换到代码中。
  • 可以用于定义枚举成员。

readonly 关键字

readonly 关键字用于声明运行时常量。运行时常量是指在运行时才能确定值且不能更改的常量。

readonly 常量可以在声明时初始化,也可以在构造函数中初始化。例如,以下代码声明了一个名为 MAX_SIZE 的运行时常量,其值在构造函数中初始化:

class MyClass {
  public readonly int MAX_SIZE;

  public MyClass() {
    MAX_SIZE = 100;
  }
}

运行时常量具有以下特点:

  • 值在运行时才能确定,因此可能会受到运行环境的影响。
  • 性能略低于编译时常量,因为编译器需要在运行时获取常量值。
  • 不能用于定义枚举成员。

总结

以下是 constreadonly 的总结:

特性 const readonly
常量类型 编译时常量 运行时常量
初始化时机 声明时 声明时或构造函数中
值来源 字面量或其他编译时常量 任意表达式
性能 较高 较低
用途 定义数学常量、枚举成员 定义配置参数、常量表达式

C#中如何运算符重载

运算符重载(Operator overloading)是 C# 中一项重要的功能,它允许程序员为自定义类型定义新的运算符。这意味着您可以让您的自定义类型像内置类型一样使用运算符,例如 +-*/ 等。

运算符重载的基本规则

运算符重载必须遵循以下基本规则:

  • 只能重载静态运算符,不能重载实例运算符。
  • 运算符重载方法必须使用 publicstatic 修饰符。
  • 运算符重载方法的返回类型必须与重载的运算符的返回类型兼容。
  • 运算符重载方法的参数个数必须与重载的运算符的参数个数一致。

运算符重载的语法

以下是运算符重载的语法:

public static return_type operator operator_symbol(parameters)
{
  // 方法体
}

其中:

  • return_type 是运算符重载方法的返回类型。
  • operator_symbol 是要重载的运算符符号。
  • parameters 是运算符重载方法的参数列表。

例如,以下代码重载了加法运算符 +,用于两个 Complex 类型的对象:

class Complex {
  public double Real { get; set; }
  public double Imaginary { get; set; }

  public Complex(double real, double imaginary) {
    Real = real;
    Imaginary = imaginary;
  }

  public static Complex operator +(Complex c1, Complex c2) {
    return new Complex(c1.Real + c2.Real, c1.Imaginary + c2.Imaginary);
  }
}

在这个例子中,operator + 方法重载了加法运算符 +,用于两个 Complex 类型的对象。该方法的返回类型是 Complex,参数列表中包含两个 Complex 类型的参数。

运算符重载的注意事项

在重载运算符时,需要注意以下事项:

  • 运算符重载应该保持语义一致性。这意味着重载的运算符应该与内置运算符具有相同的语义。例如,如果重载了加法运算符 +,则应该使 a + b 等价于 b + a
  • 运算符重载应该考虑性能。重载的运算符应该尽可能高效,避免不必要的性能开销。
  • 运算符重载应该谨慎使用。过度使用运算符重载可能会使代码变得难以理解和维护。

运算符重载的示例

以下是一些运算符重载的示例:

  • 重载加法运算符 +,用于两个 Complex 类型的对象:
class Complex {
  // ...
  public static Complex operator +(Complex c1, Complex c2) {
    // ...
  }
}
  • 重载减法运算符 -,用于两个 Point 类型的对象:
class Point {
  public int X { get; set; }
  public int Y { get; set; }

  public static Point operator -(Point p1, Point p2) {
    return new Point(p1.X - p2.X, p1.Y - p2.Y);
  }
}

C#中的ref和out参数

refout都是C#中用于传递参数引用的关键字,但它们在用法和功能上有所不同。

ref参数

ref参数用于按引用传递参数。这意味着在方法中对ref参数的任何更改都将反映在调用者的原始变量中。

例如,以下代码将一个整数变量 x 传递给 Swap 方法:

int x = 10;
int y = 20;

Swap(ref x, ref y);

Console.WriteLine("x = " + x); // 输出:x = 20
Console.WriteLine("y = " + y); // 输出:y = 10

Swap 方法使用ref参数来交换 xy 的值。在方法内部,xy 的值实际上是同一个内存地址,因此对其中一个变量的更改都会影响另一个变量。

ref参数必须在传递之前初始化。如果ref参数未初始化,则会导致编译错误。

out参数

out参数也用于按引用传递参数,但与ref参数不同的是,out参数在传递之前不需要初始化。此外,out参数必须在方法返回之前赋值

例如,以下代码将一个字符串变量 name 传递给 GetFullName 方法:

string name = "";

GetFullName(out name, out string surname);

Console.WriteLine("name = " + name); // 输出:name = John
Console.WriteLine("surname = " + surname); // 输出:surname = Doe

GetFullName 方法使用out参数来获取一个人的姓名和姓氏。在方法内部,namesurname 的值最初为空,但方法会在返回之前将这两个变量赋值为实际的姓名和姓氏。

out参数通常用于从方法返回多个值的情况。例如,以下代码使用out参数来返回一个矩形的面积和周长:

int width = 5;
int height = 3;

int area;
int perimeter;

GetRectangleAreaAndPerimeter(width, height, out area, out perimeter);

Console.WriteLine("Area = " + area); // 输出:Area = 15
Console.WriteLine("Perimeter = " + perimeter); // 输出:Perimeter = 16

GetRectangleAreaAndPerimeter 方法使用out参数来返回矩形的面积和周长。在方法内部,areaperimeter 的值最初为空,但方法会在返回之前将这两个变量赋值为实际的面积和周长。

总结

以下是ref和out参数的总结:

特性 ref out
初始化 必须在传递之前初始化 不需要初始化
赋值 可以不赋值 必须在返回之前赋值
用途 双向传递参数值 从方法返回多个值

C#中如何定义和使用索引器

索引器(Indexer)是 C# 中一种特殊属性,它允许类或结构的实例像数组一样使用下标的方式进行访问。这意味着您可以使用方括号 [] 来访问类或结构的成员,就像访问数组元素一样。

定义索引器

要定义索引器,您需要在类或结构中声明一个名为 this 的特殊方法,并使用方括号 [] 指定参数列表。例如,以下代码定义了一个名为 MyCollection 的类,该类包含一个整型数组,并定义了一个索引器来访问数组元素:

class MyCollection {
  private int[] items;

  public MyCollection(int size) {
    items = new int[size];
  }

  public int this[int index] {
    get {
      return items[index];
    }
    set {
      items[index] = value;
    }
  }
}

在这个例子中,this 方法有两个参数,第一个参数是索引值,第二个参数是可选的值。get 访问器用于获取索引处的元素值,set 访问器用于设置索引处的元素值。

使用索引器

索引器可以用类似于数组的方式进行使用。例如,以下代码使用索引器来访问 MyCollection 类中的元素:

MyCollection collection = new MyCollection(10);

collection[0] = 10;
int value = collection[0];

Console.WriteLine("value = " + value); // 输出:value = 10

在这个例子中,collection[0] 语句用于访问 collection 类的第一个元素,并将其值设置为 10。value = collection[0] 语句用于获取 collection 类的第一个元素的值,并将其存储在变量 value 中。

索引器的签名

索引器的签名由其参数的数目和类型所组成。它不包含索引器类型或参数的名称。如果要在相同类中声明多个索引器,则它们的签名必须不同。索引器未分类为变量;因此,索引器值不能按引用(作为 ref 或 out 参数)传递,除非其值是引用(即按引用返回。)

索引器的访问修饰符

索引器可以具有与其他成员相同的访问修饰符(例如 publicprivateprotected 等)。这可以控制对索引器的访问权限。例如,以下代码定义了一个私有索引器:

class MyCollection {
  private int[] items;

  public MyCollection(int size) {
    items = new int[size];
  }

  private int this[int index] {
    get {
      return items[index];
    }
    set {
      items[index] = value;
    }
  }
}

在这个例子中,this 方法是私有的,这意味着它只能在 MyCollection 类内部访问。因此,您不能从类的外部使用索引器来访问数组元素。

索引器的重载

索引器可以被重载。这意味着您可以为同一个类定义多个索引器,每个索引器具有不同的参数列表或返回值类型。例如,以下代码定义了两个索引器,用于访问 MyCollection 类的元素:

class MyCollection {
  private int[] items;

  public MyCollection(int size) {
    items = new int[size];
  }

  public int this[int index] {
    get {
      return items[index];
    }
    set {
      items[index] = value;
    }
  }

  public string this[string key] {
    get {
      // ...
    }
    set {
      // ...
    }
  }
}

在这个例子中,第一个索引器使用整型索引来访问数组元素,第二个索引器使用字符串索引来访问数组元素。

索引器的用法

索引器可以用在各种场景中,例如:

  • 实现自定义集合类。
  • 提供对复杂数据结构的更直观访问方式。
  • 替代冗长的条件判断语句。

C#的空条件运算符(?.)

在 C# 中,问号 (?) 用于两种主要目的:

  1. 空条件运算符 (?.): 问号用于空条件运算符 (?.) 的一部分,该运算符是安全访问可空引用类型成员的一种方式。空条件运算符可防止如果引用为 null 则抛出 NullReferenceException 异常。

例如,考虑以下代码:

class Person
{
    public string Name { get; set; }
}

Person person = null;

string name = person?.Name; // 这不会抛出 NullReferenceException 异常

在这个例子中,person 是一个可空引用类型,目前为 null。空条件运算符 (?.) 用于访问 personName 属性。如果 person 为 null,则表达式 person?.Name 将评估为 null。这可防止抛出 NullReferenceException 异常。

  1. 三元运算符 (条件运算符): 问号还用于三元运算符 (?:) 的一部分,三元运算符是一种简写形式的 if-else 语句。三元运算符有三个操作数:条件、如果条件为真则返回的值以及如果条件为假则返回的值。

例如,考虑以下代码:

int age = 18;
string message = age >= 21 ? "您成年了。" : "您未成年。";
Console.WriteLine(message); // 输出:您成年了。

在这个例子中,三元运算符用于确定 message 变量的值。条件是 age >= 21。如果条件为真,则返回值 "您成年了。"。如果条件为假,则返回值 "您未成年。"。

以下表格总结了 C# 中问号的两种用法:

用法 描述 例子
空条件运算符 (?.) 安全访问可空引用类型成员 string name = person?.Name;
三元运算符 (?:) 简写 if-else 语句 string message = age >= 21 ? "您成年了。" : "您未成年。";

posted on   AndreaDO  阅读(19)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
点击右上角即可分享
微信分享提示