Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/294.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在C中强制使用命名参数#_C#_.net_C# 4.0_Named Parameters - Fatal编程技术网

C# 在C中强制使用命名参数#

C# 在C中强制使用命名参数#,c#,.net,c#-4.0,named-parameters,C#,.net,C# 4.0,Named Parameters,C#4引入了一个名为 int RegisterUser(string nameFirst, string nameLast, string nameMiddle, string email) 有没有办法强制使用命名参数?可能是某个属性应用于我不知道的方法或编译器开关?我想这可以通过代码检查器工具来完成,但我只是想知道是否还有其他方法 p、 美国 对于那些感兴趣的人来说,为什么需要它,为什么不使用类/结构来利用它,有一些场景是不可能的。比如对不在您控制范围内的库的调用或者您必须遵守的奇怪的代码约

C#4引入了一个名为

int RegisterUser(string nameFirst, string nameLast, string nameMiddle, string email)
有没有办法强制使用命名参数?可能是某个属性应用于我不知道的方法或编译器开关?我想这可以通过代码检查器工具来完成,但我只是想知道是否还有其他方法

p、 美国

对于那些感兴趣的人来说,为什么需要它,为什么不使用类/结构来利用它,有一些场景是不可能的。比如对不在您控制范围内的库的调用或者您必须遵守的奇怪的代码约定。

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


您可以或通过强制执行此操作—正如评论中指出的,这可能是您感兴趣的StyleCop规则(多亏了Kris)。

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

以下是解决方案:

    int RegisterUser(
#if DEBUG
      int _ = 0,
#endif
      string nameFirst = null,
      string nameLast = null,
      string nameMiddle = null,
      string email = null) { /*...*/ }
第一个参数是一个不应该使用的伪参数(为了提高效率,在发行版中被编译掉)。但是,它确保必须命名以下所有参数

有效用法是命名参数的任意组合:

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

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

我还找到了一种强制命名参数的方法。可选参数可能很危险,特别是如果您有多个相同类型的参数。重载几乎总是一个更安全的解决方案,但有时您有一个可以接受多个参数组合的方法,因此创建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("Bob", "Slob", new UserRegistrationArguments { nameMiddle = "Teh" }); 
可以这样称呼:

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(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)
…并这样做:

public class UserRegistrationArguments
{
    public string nameFirst { get; set; }
    public string nameLast { get; set; }
    public string nameMiddle { get; set; }
    public string email { get; set; }
}
RegisterUser("Bob", "Slob", new UserRegistrationArguments { nameMiddle = "Teh" }); 
这样,您只有一个可选参数,这是您的可选参数


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

我正在使用另一种方法。在我的设置中,我有一个我一直期望的参数,然后是一组可选字符串,我真的希望确保用户主动选择。所以我在这个列表中的第一个字符串是一个“trap”值,如果设置它,就会抛出一个错误。像这样:

    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.");

    }

希望你喜欢:)

对不起,我插了个无耻的插头
我实现了一个使用命名参数强制方法

因此,如果您在应使用命名参数调用的方法之前添加了一条特殊注释:

//[RequireNamedArgs]
int RegisterUser(string nameFirst, string nameLast, string nameMiddle, string email)
如果调用方试图使用位置参数而不是命名参数,分析器将发出错误

让我们看看它的实际效果:


如果您决定试一试,请自行承担风险:)

除非您的参数大部分是可选的,否则我看不出命名参数有多大用处。@BobKaufman我猜是相反的。编译代码时,它会“忘记”它是被称为位置参数、命名参数还是默认值。@事实上,当一个方法签名包含许多相同类型的参数时,调用它时很容易出错。因此,这是您要强制执行的约定。那么我认为您应该遵循FxCop规则。@BrunoBrant命名参数使代码更加自我记录,因此更易于维护。例如,有多少API必须为行和列传入整数?我打赌10次中有9次,人们必须去检查方法签名,以确保参数位于正确的位置(包括编写和读取代码的参数)。命名参数使整个练习变得无关紧要。您不能创建自定义的FxCop规则,因为FxCop规则处理的是二进制文件,而不是源代码,并且命名参数“被编译掉”。我想你可以制定一个自定义的StyleCop规则。@KrisVandermotten,我想你是对的,但是FxCop可以从PDB中提取信息,但是我不知道命名参数的使用是否会进入PDB。如果不是这样的话,我想需要一个样式cop规则来代替。不,至于命名参数是PDB:“计算机说不!”。对于一个插件,很抱歉,我实现了一个使用命名参数强制方法。如果您决定试一试--请自行承担风险:)使用编译器预处理器指令,如果未定义调试符号,它的行为就好像
int\u0
甚至不存在一样,因此对发布版本没有任何影响。。。我不认为这个答案与您认为的答案有什么不同……其效果是,未使用的带有默认值的“_”参数强制以下其余参数具有默认值,并在调用时命名。丑陋但聪明。伪参数也显示在intellisense/R#中,这是一个耻辱!同意。复杂的方法签名是一种代码味道,像这样的方法应该传递一个“上下文”实例。很可能它不是唯一一个具有复杂参数的方法,您会看到同一类中的相邻方法也有问题,这使得上下文对象非常实用。上下文对象的问题(我同意这通常是一个更好的解决方案!)是对象初始值设定项必须允许忽略属性初始化;i、 所有参数实际上都是可选的。