Check inside method whether some optional argument was passed

我只是一个虾纸丫 提交于 2019-11-27 15:33:17

Well, arguments are always passed. Default parameter values just ensure that the user doesn't have to explicitly specify them when calling the function.

When the compiler sees a call like this:

ExampleMethod(1);

It silently converts it to:

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

So it's not techically possible to determine if the argument was passed at run-time. The closest you could get is:

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

But this would behave identically if the user called it explicitly like this:

ExampleMethod(1, "default string");

The alternative, if you really want to have different behavior depending on whether or not a parameter is provided, is to get rid of the default parameters and use overloads instead, like this:

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
}

You can't, basically. The IL generated for these calls is exactly the same:

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

The defaulting is performed at the call site, by the compiler.

If you really want both of those calls to be valid but distinguishable, you can just use overloading:

// 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
}

You can't do this in C#.

However, you could overload the function to take differing arguments. That, by the way, is the only approach you can take in Java so you'd be in good company if you adopt it.

You can't check that, because method with optional parameters is a regular method with all parameters, including those which have default values. So, your method will be compiled into:

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

}

Default values are inserted by compiler in the call point. If you'll write

ExampleMethod(42);

Then compiler will generate call

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

You can compare if optionalstr or optionalint has value equal to default value, but you can't really say if it was provided by compiler or by developer.

You can't, so you need to find a different way to check for the "optional" parameter. You can pass in a null if the parameter isn't being used, and then check

if (optionalstr != null)
{
    // do something
}

You can also overload the method, having one taking the optional parameters and one that doesn't take the optional parameters. Also, you can make it so that the method without the optional parameters passes in nulls to one of the overloaded methods.

public void ExampleMethod(int required)
{
    ExampleMethod(required, null, 0);
}

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

}

you can not check directly but you can check it by default value. for example:

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

    if (optionalint == 10)
       return;
}

or

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

    if (required.HasValue==false)
       return;
}

Approach 2:

Also you can use override methods:

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
}

Another approach is to use 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;
}

Necromancing an old thread, but thought I'd add something.

You can use default(int) or new int()

For certain cases the default values can be used to check where an argument was passed. This works for multiple datatypes. 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;
}

This works particularly well when passing database ids where records hold unsigned integers greater than 0. So you know 0 will always be null and no ids can be negative. In other words, everything other than default(datatype) will be accepted as a passed parameter.


I would personally go with overloading methods, but another approach (which is perhaps outside the scope of this question) is to make the input parameters into a model. Then use the model force boundaries (like 10 being default parameter), which lets the model deal with the parameter, instead of the method.

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
    }
}

This forces behavior before it reaches your method.

Hope this helps someone.

Use nullable is a good solution.. see example below

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);
}

To determine whether an argument has been passed to an optional parameter

  1. Define an extremely unlikely value as the default for the parameter.
  2. If the optional parameter is a reference type such as a String, you can use null as the default value, provided this is not an expected value for the argument.
  3. In the procedure code, compare the parameter against the default value and take the appropriate action.

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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!