检查内部方法是不是传递了一些可选参数

Posted

技术标签:

【中文标题】检查内部方法是不是传递了一些可选参数【英文标题】:Check inside method whether some optional argument was passed检查内部方法是否传递了一些可选参数 【发布时间】:2014-01-20 03:05:44 【问题描述】:

如何检查是否将可选参数传递给方法?

public void ExampleMethod(int required, string optionalstr = "default string",
    int optionalint = 10)


    if (optionalint was passed)
       return;

另一种方法是使用Nullable<T>.HasValue(MSDN definitions,MSDN examples):

int default_optionalint = 0;

public void ExampleMethod(int required, int? optionalint,
                            string optionalstr = "default string")

    int _optionalint = optionalint ?? default_optionalint;

【问题讨论】:

我通常做的是给它一个默认值(在你的情况下是 fi -1)。当它的值与 -1 不同时,它已通过。你也可以使 int 可以为空(int?)并给它一个默认的 null 为什么要检查?默认的意义在于你不需要知道 @pm_2,来自 MSDN:“作为可能使用可为空类型的示例,请考虑普通布尔变量如何具有两个值:true 和 false。没有表示“未定义”的值“。” 可空类型和可选参数是一回事。 如果你只是想避免重复的常量比较(if ("default string" == "default string") 而不是真的检查参数是否被传递,你可以使用反射来获取默认值,然后与之相比。可能有点过头了,但是您应该能够更改签名中的默认参数而无需更改代码。***.com/a/29156478/586754 【参考方案1】:

使用 nullable 是一个很好的解决方案。请参见下面的示例

public static void ExampleMethod(bool? optionalBool = null)

    Console.WriteLine(optionalBool == null ? "Value not passed" : "Value passed");



public static void Main()

    ExampleMethod();
    ExampleMethod(true);
    ExampleMethod(false);

【讨论】:

【参考方案2】:

死灵一个旧线程,但我想我会添加一些东西。

您可以使用default(int)new int()

对于某些情况,默认值可用于检查参数的传递位置。这适用于多种数据类型。 https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/default-values-table

public void ExampleMethod(int optionalInt = default(int))

    if (optionalInt == default(int)) //no parameter passed
       //do something
    else  //parameter was passed
       return;

这在传递数据库 id 时特别有效,其中记录包含大于 0 的无符号整数。因此您知道 0 将始终为空,并且任何 id 都不能为负数。换句话说,除了 default(datatype) 之外的所有内容都将被接受为传递参数。


我个人会使用重载方法,但另一种方法(可能超出此问题的范围)是将输入参数放入模型中。然后使用模型力边界(比如 10 是默认参数),这让 模型处理参数,而不是方法

public class Example

    //...other properties

    private int _optionalInt;
    public int OptionalInt 
        get => _optionalInt;
        set 
            if (value <= default(int))
                throw new ArgumentOutOfRangeException("Value cannot be 0 or less");
            else if (value == 10)
                throw new ArgumentOutOfRangeException("Value cannot be 10");
            else
                _initValue = value;
         
    

    public Example(int optionalInt)
    
        OptionalInt = optionalInt; //validation check in constructor
    

这会在行为到达您的方法之前强制执行。

希望这对某人有所帮助。

【讨论】:

请注意,使用default(int)new int() 与使用0 完全相同...并且不会阻止调用者显式传入0。 正确,但是它确实提高了可读性,因为 0 可能意味着多种情况,其中默认值绝对意味着写入的内容,未分配的默认值。在这种情况下传递 0 仍然意味着预期。感谢您的澄清! “默认值绝对意味着写入的内容,未分配的默认值” - 不,他们没有。它们的意思是“该类型的默认值”——在这种情况下为 0。传入 0 将使您的代码声称调用代码没有传入它,即使它已经传入。您无法检测调用代码是否已显式传递参数。 因此在我的回答中使用了粗体 某些情况。 Default 和 0 在方法的第一行中处理为相同。代码不会阻止它们将 0 甚至 default(int) 作为参数传递(如重载),但通过设置 parameter = default(int) = new int() = 0 未初始化的含义,该方法知道该参数无关紧要,在这种情况下跳过返回;它不是最终的所有解决方案,并且肯定有它的漏洞,而是一种不同的方式,我认为它记录在这里。另外我认为== default(long)== 0 更具可读性哈哈。 我建议您进行编辑以更清楚地说明“某些情况”的含义。我将其解释为“某些情况,例如当您使用值类型并且不希望显式传递 0 时”。如果您的意思是“您可以检测传入的值是否与默认值相同,但您无法判断这是显式还是隐式完成”,那么这是一个非常不同的问题。就术语而言,该参数从不未初始化-我不确定您的意思是什么。【参考方案3】:

判断一个参数是否已经传递给可选参数

    定义一个极不可能的值作为参数的默认值。 如果可选参数是 String 等引用类型,则可以使用 null 作为默认值,前提是这不是参数的预期值。 在过程代码中,将参数与默认值进行比较并采取适当的措施。

https://msdn.microsoft.com/en-us/library/849zff9h(v=vs.100).aspx

【讨论】:

这不允许您确定调用者是否提供了值,因为调用者始终可以选择显式提供您使用的任何默认值,正如其他几个答案中所述。 @Servy ...您没有正确阅读答案..您可以再看一遍。此外,这不是我的答案,它实际上取自 Microsoft 文档,请参阅链接。 显然您实际上并没有正确阅读该问题。该问题询问如何区分没有为具有默认值的参数提供值的调用者和提供默认值的调用者。您的回答没有提供解决方案。该链接特别指出这不是解决方案,因此它对您的情况没有真正的帮助。 这个问题没有正确答案,也永远不会是正确答案。这就是微软文档强调它不是解决方案的原因。供您参考,早在 Visual Basic 5.0 中就引入了此功能。 当然有正确的答案。正确的答案是这是不可能的,正如其他答案所述,以及您链接到状态的文档。您断言实际上可能是错误的答案。我看不出添加该功能的时间与此有什么关系。另外,问题是关于 C#,而不是 VB。【参考方案4】:

另一种方法是使用Nullable&lt;T&gt;.HasValue(MSDN definitions,MSDN examples):

int default_optionalint = 0;

public void ExampleMethod(int required, int? optionalint,
                            string optionalstr = "default string")

    int _optionalint = optionalint ?? default_optionalint;

【讨论】:

【参考方案5】:

您不能,因此您需要找到一种不同的方法来检查“可选”参数。如果参数没有被使用,你可以传入一个null,然后检查

if (optionalstr != null)

    // do something

您也可以重载该方法,一个采用可选参数,一个不采用可选参数。此外,您可以使不带可选参数的方法将空值传递给重载方法之一。

public void ExampleMethod(int required)

    ExampleMethod(required, null, 0);


public void ExampleMethod(int required, string optionalstr = "default string",
int optionalint = 10)



【讨论】:

【参考方案6】:

你不能在 C# 中做到这一点。

但是,您可以重载该函数以采用不同的参数。顺便说一句,这是您在 Java 中可以采用的唯一方法,因此如果您采用它,您将是一个很好的伙伴。

【讨论】:

我想赞成这个答案,但后来我看到“Java”,我不会。 @Sinatr:确实应该受到谴责:如果我是你,我会考虑否决这个。我什至可以通过支持您的一个答案来为您提供声誉。 (说真的,我认为 Java 有它的缺点,比如像 C++ 这样成熟的语言,直到我遇到 C#。)【参考方案7】:

您不能直接检查,但可以默认检查。 例如:

public void ExampleMethod(int required, string optionalstr = "default string",
    int optionalint = 10)


    if (optionalint == 10)
       return;

public void ExampleMethod(int required, string optionalstr = "default string",
    int? optionalint)


    if (required.HasValue==false)
       return;

方法2:

你也可以使用覆盖方法:

public void ExampleMethod(int required, string optionalstr = "default string")

     //When this method called, means optionalint was NOT passed


public void ExampleMethod(int required, string optionalstr = "default string",
    int optionalint)

    //When this method called, means optionalint was passed

【讨论】:

if (required.HasValue==false) - 必需的不可为空。 如果没有 optionalInt 的默认值,方法 2 将无法编译。 @AustinSalonen 你应该一起实现两个方法,如果你在方法 2 中实现方法 2 显然它不会被编译。【参考方案8】:

嗯,参数总是被传递的。默认参数值只是确保用户在调用函数时不必显式指定它们。

当编译器看到这样的调用时:

ExampleMethod(1);

它默默地将其转换为:

ExampleMethod(1, "default string", 10);

因此,在技术上无法确定参数是否在运行时传递。你能得到的最接近的是:

if (optionalstr == "default string")
   return;

但是如果用户像这样显式调用它,它的行为会相同:

ExampleMethod(1, "default string");

如果您真的想根据是否提供参数来获得不同的行为,另一种方法是摆脱默认参数并使用重载,如下所示:

public void ExampleMethod(int required)

    // optionalstr and optionalint not provided


public void ExampleMethod(int required, string optionalstr)

    // optionalint not provided


public void ExampleMethod(int required, string optionalstr, int optionalint)

    // all parameters provided

【讨论】:

在我的问题编辑中使用可空类型参数是一个好的解决方案吗? @Yariv 这实际上并没有解决问题,它只是产生了另一个级别的间接性。用户仍然可以使用显式参数ExampleMethod(10, null) 调用它,这在运行时与ExampleMethod(10) 没有区别。尽管这可能足以满足您的目的。【参考方案9】:

你不能,基本上。为这些调用生成的 IL 完全相同相同:

ExampleMethod(10);
ExampleMethod(10, "default string");
ExampleMethod(10, "default string", 10);

编译器在调用站点执行默认设置。

如果您真的希望这两个调用都有效但可区分,则可以使用重载:

// optionalint removed for simplicity - you'd need four overloads rather than two
public void ExampleMethod(int required)

    ExampleMethodImpl(required, "default string", false);


public void ExampleMethod(int required, string optionalstr)

    ExampleMethodImpl(required, optionalstr, true);


private void ExampleMethodImpl(int required, int optionalstr, bool optionalPassed)

    // Now optionalPassed will be true when it's been passed by the caller,
    // and false when we went via the "int-only" overload

【讨论】:

【参考方案10】:

您无法检查,因为带有可选参数的方法是带有所有参数的常规方法,包括具有默认值的参数。所以,你的方法会被编译成:

public void ExampleMethod(int required, string optionalstr, int optionalint)



编译器在调用点插入默认值。如果你会写

ExampleMethod(42);

然后编译器会生成调用

ExampleMethod(42, "default string", 10);

您可以比较 optionalstroptionalint 的值是否等于默认值,但您无法确定它是由编译器还是开发人员提供的。

【讨论】:

在我的问题编辑中使用可空类型参数是一个好的解决方案吗? @Yariv with nullable 你仍然不能说是否没有提供值,或者default_optionalint 已经手动传递给你的方法。默认值只是参数可以具有的可能值之一。

以上是关于检查内部方法是不是传递了一些可选参数的主要内容,如果未能解决你的问题,请参考以下文章

检查是不是设置了 argparse 可选参数

PyTorch c++ 扩展中的可选张量

如何检查调用者是不是设置了 PowerShell 可选参数

Angular如何传递跳过一些[重复]的可选构造函数参数

FlutterDart的方法中的可选参数方法作为参数传递

防止 Obj-C 代码将 `nil` 传递给具有非可选参数的 Swift 方法