C#4.0中的更改——命名参数和可选参数

Posted DinAction

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C#4.0中的更改——命名参数和可选参数相关的知识,希望对你有一定的参考价值。

一、概念
C#中的命名参数和可选参数是两种函数参数的特殊形式,它们可以提高代码的可读性和灵活性。

命名参数

命名参数允许我们在调用函数时指定参数名称,从而不必按照函数定义时的参数顺序进行传参。这样做可以使代码更加易读易懂,同时也可以提高代码的灵活性,因为我们可以只传递某些参数来设置默认值。

以下是一个使用命名参数的示例:

void PrintPerson(string firstName, string lastName, int age) 
Console.WriteLine($"Name: firstName lastName, Age: age");


// 使用命名参数调用PrintPerson函数
PrintPerson(lastName: "Smith", firstName: "John", age: 30);

在上面的示例中,我们使用了命名参数来调用PrintPerson函数,并且没有按照函数定义时的参数顺序进行传参。由于我们指定了每个参数的名称,因此代码更加易读易懂。

注意,当我们使用命名参数时,可以省略一些参数并采用默认值,但不能跳过非可选参数。例如,下面的代码是无法编译通过的:

PrintPerson(lastName: "Smith"); // 编译错误:缺少必需的参数 \'firstName\' 和 \'age\'

可选参数

可选参数允许我们在函数定义时为某些参数指定默认值,从而在调用函数时可以不传递这些参数。这样做可以提高代码的灵活性,因为我们可以只传递需要的参数,而不必传递所有参数。

以下是一个使用可选参数的示例:

void PrintPerson(string firstName, string lastName, int age = 18) 
Console.WriteLine($"Name: firstName lastName, Age: age");


// 调用PrintPerson函数
PrintPerson("John", "Smith"); // 输出结果:Name: John Smith, Age: 18
PrintPerson("Mary", "Johnson", 25); // 输出结果:Name: Mary Johnson, Age: 25

在上面的示例中,我们定义了一个可选参数age,并将其默认值设置为18。当我们调用PrintPerson函数时,如果没有传递age参数,则会使用默认值。

注意,当我们使用可选参数时,必须将它们放在函数签名的末尾,并且不能使用ref或out关键字。例如,下面的代码是无法编译通过的:

void PrintPerson(string firstName, string lastName, ref int age = 18)  // 编译错误:可选参数不能使用ref或out关键字
Console.WriteLine($"Name: firstName lastName, Age: age");

总之,命名参数和可选参数都是C#中非常有用的语言特性,它们能够提高代码的可读性和灵活性,使程序变得更加易于维护和扩展。

二、实例

命名参数和可选参数的应用场景非常广泛,以下是一些经典的应用场景,并附有相应的代码示例:

命名参数

  1. 函数具有多个参数,但我们只关心其中的某几个参数。
void PrintPerson(string firstName, string lastName, int age) 
    Console.WriteLine($"Name: firstName lastName, Age: age");


// 使用命名参数调用PrintPerson函数,只传递了需要的参数
PrintPerson(lastName: "Smith", firstName: "John");
  1. 函数中具有相同类型的多个参数,使用命名参数可以提高代码的可读性。
void Search(int id, string name, string address) 
    // ...


// 使用命名参数调用函数Search,可以清楚地表明每个参数的含义
Search(id: 1, name: "John", address: "123 Main St.");

可选参数

  1. 函数中某些参数的默认值可能经常被使用。例如,在创建一个窗口时,我们可以将宽度和高度设置为可选参数,并将其默认值设置为800和600,因为这是大多数用户所期望的窗口大小。
void CreateWindow(int width = 800, int height = 600) 
    // ...


// 调用CreateWindow函数,不传递可选参数
CreateWindow(); // 窗口大小为800x600

// 调用CreateWindow函数,只传递一个可选参数
CreateWindow(width: 1024); // 窗口大小为1024x600

// 调用CreateWindow函数,传递两个可选参数
CreateWindow(width: 1024, height: 768); // 窗口大小为1024x768
  1. 函数中的某些参数是可选的,但如果提供了,则必须按照特定的格式进行传递。例如,在打印日志时,我们可以将时间戳设置为一个可选参数,并将其默认值设置为当前时间。
void Log(string message, DateTime timestamp = default(DateTime)) 
    if (timestamp == default(DateTime)) 
        timestamp = DateTime.Now;
    
    Console.WriteLine($"[timestamp] message");


// 调用Log函数,不传递可选参数
Log("Hello World!"); // 输出结果:[2021/10/01 12:00:00] Hello World!

// 调用Log函数,传递时间戳作为可选参数
Log("Hello World!", new DateTime(2021, 9, 30, 23, 59, 59)); // 输出结果:[2021/09/30 23:59:59] Hello World!

总之,命名参数和可选参数是一种非常有用的C#语言特性,它们能够提高代码的可读性和灵活性。在实际开发中,我们应该根据具体场景选择合适的参数传递方式,以使代码更加清晰易懂。

通用方法和可选参数

【中文标题】通用方法和可选参数【英文标题】:Generic methods and optional arguments 【发布时间】:2012-04-11 00:51:54 【问题描述】:

可以写出类似的结构吗? 我想以某种方式为 T 类型的参数设置默认值。

    private T GetNumericVal<T>(string sColName, T defVal = 0)
    
        string sVal = GetStrVal(sColName);
        T nRes;
        if (!T.TryParse(sVal, out nRes))
            return defVal;

        return nRes;
    

另外,我发现了以下链接: Generic type conversion FROM string 我认为,这段代码必须有效

private T GetNumericVal<T>(string sColName, T defVal = default(T)) where T : IConvertible

    string sVal = GetStrVal(sColName);
    try
    
        return (T)Convert.ChangeType(sVal, typeof(T));
    
    catch (FormatException)
    
        return defVal;
                

【问题讨论】:

【参考方案1】:

我没有尝试过,但将T defVal = 0更改为T defVal = default(T)

【讨论】:

【参考方案2】:

如果你知道 T 会有一个无参数的构造函数,你可以这样使用 new T():

private T GetNumericVal<T>(string sColName, T defVal = new T()) where T : new()

否则你可以使用默认(T)

private T GetNumericVal<T>(string sColName, T defVal = default(T))

【讨论】:

【参考方案3】:

回答设置默认值的问题

private T GetNumericVal<T>(string sColName, T defVal = default(T)) 

    string sVal = GetStrVal(sColName);
    T nRes;
    if (!T.TryParse(sVal, out nRes))
        return defVal;

    return nRes;

但是你不能调用静态 TryParse 方法,因为编译器无法知道类型 T 声明了这个静态方法。

【讨论】:

是的,我不能调用 TryParse。但也许类似的东西?也许为类型参数添加一些约束(我的意思是'where:...')?如果数字类型实现了一些转换接口。 CLR 没有“虚拟静态方法”的概念,编译器无法从类型推断静态方法。据我所知,没有干净的解决方案。 ***.com/questions/196661/… 了解更多详情

以上是关于C#4.0中的更改——命名参数和可选参数的主要内容,如果未能解决你的问题,请参考以下文章

11年 C# 4.0四大新特性代码示例与解读

C#4.0中的方法重载与可选参数[重复]

C# 4 中的重载分辨率和可选参数

C#中可选参数和具名参数的使用

C# 4.0,可选参数和参数不能一起工作

Mathematica 中的可选命名参数