常用的高级参数类型:

  1. 可选参数(Optional Parameters):在定义方法时,可以给某些参数赋一个默认值,从而让调用该方法时不必传入这些参数。这样可以让方法更加灵活,调用起来也更加方便。举个例子:
    1
    2
    3
    4
    public void SayHello(string name, int age = 18)
    {
    Console.WriteLine($"Hello, {name}, your age is {age}");
    }
    在这个方法中,age参数被指定了默认值18,因此在调用该方法时可以不传入age参数,比如:
    1
    SayHello("Tom");  // Hello, Tom, your age is 18
  2. 命名参数(Named Parameters):在调用方法时,可以通过指定参数名的方式来传递参数,这样可以让代码更加易读易懂。例如:
    1
    SayHello(age: 20, name: "Tom");  // Hello, Tom, your age is 20
  3. 可变参数(Variable Parameters):在定义方法时,可以使用params关键字来声明一个可变参数,这样可以让方法接受任意个数的参数。例如:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    public void AddNumbers(params int[] numbers)
    {
    int sum = 0;
    foreach (int n in numbers)
    {
    sum += n;
    }
    Console.WriteLine($"The sum of numbers is {sum}");
    }
    在这个方法中,我们使用了params关键字来声明一个可变参数numbers,这样就可以接受任意个数的int类型参数。例如:
    AddNumbers(1, 2, 3); // The sum of numbers is 6
    AddNumbers(1, 2, 3, 4, 5); // The sum of numbers is 15
  4. 输出参数(Out Parameters):在调用方法时,可以使用out关键字来声明一个输出参数,该参数可以在方法内部被修改,并且方法结束后将输出参数的值返回给调用者。例如:
    1
    2
    3
    4
    5
    public void Divide(int x, int y, out int quotient, out int remainder)
    {
    quotient = x / y;
    remainder = x % y;
    }
    在这个方法中,我们使用out关键字来声明两个输出参数quotient和remainder,该方法计算x除以y的商和余数,并将结果分别存入输出参数中。例如:
    1
    2
    3
    int q, r;
    Divide(10, 3, out q, out r);
    Console.WriteLine($"The quotient is {q}, and the remainder is {r}"); // The quotient is 3, and the remainder is 1
  5. ref参数(Ref Parameters):在调用方法时,可以使用ref关键字来声明一个引用参数,该参数可以在方法内部被修改,并且方法结束后将修改后的值返回给调用者。与out参数不同的是,ref参数在调用时必须已经被初始化。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    class Program
    {
    static void Main(string[] args)
    {
    int value = 5;
    Console.WriteLine("Before: " + value);
    ChangeValue(ref value);
    Console.WriteLine("After: " + value);
    }

    static void ChangeValue(ref int x)
    {
    x = 10;
    }
    }

接口

  1. C# 中的接口是一种定义一组方法、属性和事件的抽象类型。接口定义了一个类或结构体必须实现的成员列表,但不提供实现。这使得多个类或结构体可以实现同一接口,从而达到多态的目的。
    接口有以下几个用途:
  1. 定义标准:接口定义了一组标准的方法、属性和事件,用于实现类或结构体的行为。这些标准可以用于规范代码的实现,提高代码的可读性和可维护性。

  2. 实现多态:多个类或结构体可以实现同一接口,从而达到多态的目的。这种多态性可以提高代码的灵活性和可扩展性。

  3. 分离接口和实现:接口定义了一组方法、属性和事件,但不提供实现。这使得接口和实现可以分离,从而降低代码的耦合度,提高代码的可维护性和可扩展性。

  4. 提供框架:接口可以作为框架的一部分,使得其他开发人员可以实现接口,从而扩展框架的功能。

  1. 什么时候继承接口,什么时候继承类?
    在 C# 中,继承接口和继承类都是实现代码复用的方式。通常情况下,应该优先选择继承接口,而不是继承类。下面是一些基本的指导原则:

当你需要定义一组方法、属性和事件的规范时,应该使用接口。接口定义了一组标准,使得多个类或结构体可以实现相同的行为,从而实现多态性。在这种情况下,应该优先使用接口。

当你需要实现代码的复用时,可以使用类或结构体。类或结构体可以继承另一个类或结构体的成员,从而实现代码复用。在这种情况下,应该优先使用类或结构体。

如果你需要同时实现接口的规范和代码的复用,可以使用抽象类。抽象类可以提供一些默认的实现,同时也可以定义一些抽象的方法或属性,这些方法或属性必须在派生类中实现。在这种情况下,应该使用抽象类。

需要注意的是,C# 中的类只支持单继承,也就是说一个类只能继承一个类。但是一个类可以实现多个接口,因此接口更加灵活和可扩展。当你需要实现多态性和代码复用时,应该优先选择接口。

数据类型转换

  1. 隐式类型转换:当将一个小范围的数据类型的值赋值给一个大范围的数据类型时,C#会自动将小范围的数据类型隐式地转换为大范围的数据类型。例如,将一个整数赋值给一个长整数或将一个单精度浮点数赋值给一个双精度浮点数等。
    1
    2
    3
    4
    int i = 10;
    long l = i; // 隐式转换为long类型
    float f = 3.14f;
    double d = f; // 隐式转换为double类型
  2. 显式类型转换:当需要将一个大范围的数据类型转换为一个小范围的数据类型时,C#需要显式地将数据类型转换为目标类型。显式类型转换可以通过将源数据类型放在圆括号中,并在其前面添加目标数据类型来实现。但是,如果源数据类型的值超出了目标数据类型的范围,可能会导致数据丢失或不准确。
    1
    2
    double d = 3.14;
    int i = (int)d; // 显式转换为int类型
  3. 装箱和拆箱:装箱是将值类型转换为引用类型的过程,而拆箱是将引用类型转换为值类型的过程。装箱和拆箱在使用上较为复杂,需要注意避免出现性能问题。
    1
    2
    3
    int i = 10;
    object o = i; // 装箱,将i转换为object类型
    int j = (int)o; // 拆箱,将o转换为int类型
  4. Parse和TryParse方法:Parse方法将字符串转换为指定的数据类型,而TryParse方法则尝试将字符串转换为指定的数据类型,如果转换失败,则返回false。这些方法主要用于从用户输入或文件读取等操作中获得数据。
    1
    2
    3
    string str = "123";
    int i = int.Parse(str); // 将字符串转换为int类型
    bool success = int.TryParse(str, out int j); // 尝试将字符串转换为int类型
  5. Convert类的方法:Convert类提供了一组方法,用于将一种数据类型转换为另一种数据类型。Convert类中的方法适用于所有数据类型,并提供了更多的转换选项。
    1
    2
    3
    string str = "123";
    int i = Convert.ToInt32(str); // 将字符串转换为int类型
    double d = Convert.ToDouble(i); // 将int类型转换为double类型
    在使用数据类型转换时,需要注意转换的目标数据类型的范围和精度,以避免数据丢失或不准确。此外,尽量使用安全的转换方法,如TryParse或Convert类的方法,并对转换结果进行检查。
1