65.9K
CodeProject 正在变化。 阅读更多。
Home

为 C# 添加默认参数

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.54/5 (18投票s)

2007年4月21日

CPOL

5分钟阅读

viewsIcon

136688

downloadIcon

577

一个小的代码生成器,用于生成必要的重载以支持默认参数

Screenshot - DefaultOverloader.png

更新于 2007 年 12 月

  • 构造函数重载支持
  • 自动粘贴
  • Linkify 集成

引言

开始学习 C# 时,最大的烦恼之一就是缺少默认参数。手动生成两三个重载是可以接受的,但看到 MessageBox 的 28 个重载,就让我头晕目眩(而且是难受的那种)。

现在我无法修改 C# 编译器以使其神奇地支持此功能。但我可以提供一个代码生成器,它可以从包含默认参数的声明中创建一组重载。

使用工具

在第一个编辑框中输入你的声明。你可以像在 C++ 中一样添加默认参数,生成的代码会立即显示在下面的文本字段中。单击“复制”将生成的代码复制到剪贴板。示例

void Add(string name = "(none)", int age = 22)

以上代码生成以下实现

// $overload: void Add(string name = "(none)", int age = 22){
 // do your worst! - implement the actual method here
}

#region overloads for: Add

public void Add(string name)
{
 Add(name, 22);
}

public void Add()
{
 Add("(none)", 22);
}

#endregion // overloads
public void Add(string name, int age)

第一个重载是你实际实现的那个方法。其他重载的参数列表已缩减,并调用第一个方法。

第一行是用于与 Linkify 集成的(见下文)。

变得更好(可选)

C++ 默认参数允许省略参数列表末尾的参数。但是,在上面的示例中,当参数类型不同时,你可能希望省略名称但仍指定年龄。我添加了一个自定义“关键字”`optional`,它可以从参数列表的中间删除参数。

void Add(optional string name = "(none)", int age = 22)

这将生成以下签名

public void Add(string name, int age) { } // the one to implement
public void Add(string name)
public void Add()
public void Add(int age)

最后一个省略了 string name 参数。

确保生成的重载没有歧义是你的责任。如果你觉得无法胜任,编译器会捕获你!

与 Visual Studio 集成 - Linkify

我更新了我的 Linkify 文章,它允许从源代码注释中访问 URL 和运行外部工具。此外,DefaultOverloader 现在生成 Linkify 可以理解的声明行。

// $overload: void Add(string name = "(none)", int age = 22)
void Add(string name, int age)

注意:你需要在 Linkify 配置对话框中先设置 DefaultOverloader 可执行文件的路径。有关详细信息,请参阅该文章。

将光标放在“$overload”上,然后单击“Linkify”。Default Overloader 会打开,并将你的声明已就位。

你也可以通过单击“copy head”分别复制两行声明,“copy body”复制重载区域。这允许保留主函数实现的函数体。自动粘贴使这一切变得更加容易。

自动粘贴

自动粘贴使这一切变得更加容易。它可以在没有安装 Linkify 的情况下工作(但那时,第一步会更复杂)。要修改现有的重载块

  1. 将光标放在“$overload”上,然后启动 Linkify
    » DefaultOverloader 将打开,你的声明已准备好进行编辑。
  2. 进行修改后,单击“Auto-Paste”
    » DefaultOverloader 最小化,并显示“Paste Head”作为标题
  3. 选择两行头部(注释和主函数头),然后粘贴
    » 声明被新内容替换
    » DefaultOverloader(仍然最小化)显示“Paste Body”作为标题
  4. 折叠 #region Overloads for...,选择整行,然后粘贴
    » 新的重载替换了之前的重载
    » DefaultOverloader 关闭

从最小化状态恢复 DefaultOverloader 以取消粘贴序列。第一个粘贴和第二个数据到达剪贴板之间有一个很小的延迟,所以不要连续粘贴得太快!

限制

解析器相当简单。所以你可能能够创建一些解释不正确的声明。一个问题是函数名带有多个模板参数:不要在模板列表中留空格,否则我将错误地识别函数名!

解析器不验证你的声明 - 这取决于你的编译器。

这不幸地不是默认参数的完整替代品。一些语言和 IDE 支持会很有帮助的一个方面是智能感知(Intellisense)——你仍然会单独列出所有重载。而且,当你修改声明时,你必须再次使用 Overloader。

争论

MSIL 或 C# 语言中没有默认参数是有原因的——要了解原因,请阅读 Eric Gunnersons 的回复 [^] 或者 在 Google 上搜索 [^]。

依我看,Eric 关于默认参数不在 MSIL 中的论点是站得住脚的——但这对 C# 语言本身并不适用。毕竟,C# 可以做我所做的。

关注点

布尔值的排列

为了实现 `optional` 关键字,我需要对包含它的所有变体进行排列。对于带有 `optional` 标记的 `N` 个参数,我需要生成 `N` 个布尔值的 `bool` 数组的所有可能组合。虽然网上可以找到一些方法,但没有一种对我来说是即插即用的。在思考如何自己实现它时,一个“后台线程”将 `bool` 数组的想法与 `bit` 数组联系了起来——`bool` 就是 `bit`!这允许一个非常简单的解决方案:只需从 `0` 数到 `2^N - 1`,并将每个位视为一个标志。

解析参数列表

源代码中包含一个(仍处于实验阶段的)分词器,它可以识别单引号和双引号字符串以及圆括号、方括号和花括号。这对于正确解析以下声明至关重要

SendMessage(string X = "Hello, World", int[,] targetCoords) 

它几乎未经测试,需要一些扩展才能重用,但对于给定应用程序来说,它已经足够好用了。

谢谢

非常感谢所有在 C# 论坛上帮助过我的人——特别是 Judah Himango,他经常付出额外的努力。

我目前正在进行我的第一个 “真实世界” C# 项目(有时间压力、功能蔓延、宏伟计划,以及在每个人都试图分散你注意力时完成任务),你们在我克服这个难题(或者至少是“进入”这个难题)的过程中给予了极大的帮助。

历史

  • 2007 年 4 月 21 日
    • 首次上传
  • 2007 年 4 月 23 日
    • 修复了文章文本中的复制粘贴错误
  • 2007 年 12 月 16 日
    • 自动检测构造函数,并生成正确的重载
    • 可以单独复制头部和重载体
    • 自动粘贴,用于连续粘贴
    • Linkify 集成(需要 2007 年 12 月版本!)
© . All rights reserved.