在C#中强制命名参数

时间:2012-07-02 20:23:40

标签: c# .net c#-4.0 named-parameters

C#4引入了一个名为named arguments的功能,在

等场景中特别有用
int RegisterUser(string nameFirst, string nameLast, string nameMiddle, string email)

有没有办法强制使用命名参数?也许某些属性适用于我不知道的方法或编译器开关?我想可以使用代码检查器工具完成,但只想知道是否还有其他方法。

P.S。

对于那些感兴趣的人为什么可能需要它,为什么不使用类/结构来利用object initializers,有些情况是不可能的。就像调用不在您控制中的库或您必须遵守的奇怪代码约定一样。

5 个答案:

答案 0 :(得分:26)

不,不是用C#语言。如果提供了所有参数,它将始终接受位置参数。

你可以build a custom FxCop ruleStyleCop rule强制执行此操作 - 正如评论中所指出的,它可能是你感兴趣的StyleCop规则(感谢Kris)。

答案 1 :(得分:25)

可以强制调用者始终使用命名args。我不会在大多数情况下这样做,因为它相当丑陋,但这取决于需要多么安全的方法使用。

以下是解决方案:

    int RegisterUser(
#if DEBUG
      int _ = 0,
#endif
      string nameFirst = null,
      string nameLast = null,
      string nameMiddle = null,
      string email = null) { /*...*/ }

第一个参数是一个不应该使用的虚拟参数(为了提高效率而在Release中编译)。但是,它确保必须命名所有后续参数。

有效用法是指定参数的任意组合:

    RegisterUser();
    RegisterUser(nameFirst: "Joe");
    RegisterUser(nameFirst: "Joe", nameLast: "Smith");
    RegisterUser(email: "joe.smith@example.com");

尝试使用位置参数时,代码将无法编译。

答案 2 :(得分:3)

我也试图强制命名参数。可选参数可能很危险,尤其是如果您有多个相同类型的参数。重载几乎总是一个更安全的解决方案,但有时你有一个方法可以采用多种参数组合,因此创建20个重载来解释可能性是过度的。

在最重要的情况下,参数必须始终被命名,我将创建一个没有定义构造函数的参数类。在您的情况下,您可以这样做:

public class UserRegistrationArguments
{
    public string nameFirst { get; set; }
    public string nameLast { get; set; }
    public string nameMiddle { get; set; }
    public string email { get; set; }
}

这样称呼:

RegisterUser(new UserRegistrationArguments { nameFirst = "Bob", nameLast = "Slob" });

你也可以像这样简化:

public class UserRegistrationArguments
{
    public string nameMiddle { get; set; }
    public string email { get; set; }
}

int RegisterUser(string nameFirst, string nameLast, UserRegistrationArguments args = null)

......并且这样做:

RegisterUser("Bob", "Slob", new UserRegistrationArguments { nameMiddle = "Teh" }); 

这样,您只有一个可选参数,可用于您的可选参数。

编辑:也许我没有正确读取OP。你没有使用可选参数?如果没有,那么这个答案可能对你没有帮助。

答案 3 :(得分:1)

对不起,请插入无耻的插头!
我实现了Roslyn analyzer来强制对方法使用命名参数。

因此,如果您install the RequireNamedArgs analyzer并在应使用命名参数调用的方法之前添加特殊注释:

//[RequireNamedArgs]
int RegisterUser(string nameFirst, string nameLast, string nameMiddle, string email)

如果调用者尝试使用位置参数而不是命名参数,则分析器将发出错误。

看看实际情况:enter image description here

如果您决定尝试一下-后果自负:)

答案 4 :(得分:0)

我正在使用其他方法。在我的设置中,我有一个我一直期望的参数,然后来了一堆可选的字符串,我真的想确保用户主动选择。所以我在这个列表中的第一个字符串是"陷阱" value,如果设置,则抛出错误。像这样:

    public HtmlString Toolbar(DynamicEntity target = null, string dontRelyOnParameterOrder = Constants.RandomProtectionParameter, string actions = null, string contentType = null, object prefill = null)
    {
        if (!Enabled) return null;
        protectAgainstMissingParameterNames(dontRelyOnParameterOrder);

        var toolbar = new ItemToolbar(target, actions, contentType, prefill);

        return new HtmlString(toolbar.Toolbar);
    }

    private void protectAgainstMissingParameterNames(string criticalParameter)
    {
        if(criticalParameter != Constants.RandomProtectionParameter)
            throw new Exception("when using the toolbar command, please use named parameters - otherwise you are relying on the parameter order staying the same.");

    }

希望你喜欢它:)