Question

I wrote a method that takes optional parameter

public void ExampleMethod(int maxValue = 20)
{
  ...
}

and i will use it as

int param = GetSomeValue();
ExampleMethod(param < 20 ? param : use_your_default_value_as_specified);

if it is less than 20, use param, else use your own default value implemented in ExampleMethod (in this example it's 20).. How can i tell that "use_your_default_value_as_specified" to compiler ?

I know i can do this by

int param = GetSomeValue();
ExampleMethod(param);

public void ExampleMethod(int maxValue)
{
  if(maxValue > 20)
      maxValue = 20;
}

but i want to send the correct value before execution of ExampleMethod

Was it helpful?

Solution 2

This is kinda awkward, but it does allow you to retrieve default parameters. Once you have the value, you can combine it with my answer above to get where you want to go.

This is in LINQPad format.

void Main()
{
    Console.WriteLine(AddEm());

    Console.WriteLine("Default for parm1 is " + GetDefaultParm<int>   (GetType().GetMethod("AddEm"), "parm1"));
    Console.WriteLine("Default for parm2 is " + GetDefaultParm<int>(GetType().GetMethod("AddEm"), "parm2"));
    Console.WriteLine("Default for parm3 is " + GetDefaultParm<int>(GetType().GetMethod("AddEm"), "parm3"));
}

private T GetDefaultParm<T>(MethodInfo m, string parmname) {
    var parm = m.GetParameters().Where(p => p.Name == parmname).FirstOrDefault();
    if (parm != null) {
        return (T) parm.DefaultValue;
    } 
    throw new Exception("Parameter not found.");
}   


// Define other methods and classes here
public int AddEm(int parm1 = 10, int parm2 = 20, int parm3 = 30) {
    return parm1 + parm2 + parm3;
}

Output:

60
Default for parm1 is 10
Default for parm2 is 20
Default for parm3 is 30

OTHER TIPS

The only way to tell the compiler to use the default value for a parameter is not to specify it at all.

You could use some reflection kludgery to get the value at run time:

public static object DefaultValueForParameter(Type type, string methodName, int parameterNumber)
{
    return type.GetMethod(methodName).GetParameters()[parameterNumber].DefaultValue;
}

ExampleMethod(param < 20 ? param : (int)DefaultValueForParameter(this.GetType(), "ExampleMethod", 0));

But that's not very elegant or efficient.

You could refactor ExampleMethod to take nullable arguments instead, like this:

public void ExampleMethod(int? maxValue = null)
{
    if(maxValue.HasValue)
        maxValue = 20;
}

ExampleMethod(param < 20 ? (int?)param : null);

In this way, the actual default value is hidden within the function. Itself, I know this looks a lot like the code you said you don't want to use, there is a key difference. It separates the logic of what values can be passed in, from the what the default value should be. In the solution you stated you didn't want to use, it would be impossible to use 10 as a maxValue, because it would be overridden within your method.

You could also refactor this so that the default value is a publicly available constant, like so:

const int DefaultMaxValue = 20;

public void ExampleMethod(int? maxValue = DefaultMaxValue)
{
    maxValue.Dump();
}

ExampleMethod(param < 20 ? param : DefaultMaxValue);

This way, you get the benefit of having a default value which you can use in multiple places in your code without having to specify it every time.


Still, if you don't like any of the solutions above, you can stick with simplest method of all. I know it's not exactly what you're looking for, but I'd probably go with this:

if (param < 20)
    ExampleMethod(param)
else 
    ExampleMethod();

Also note that if ExampleMethod returned a something other than void, you could do this:

var result = param < 20 ? ExampleMethod(param) : ExampleMethod();

Could you do with a class?

// Individual Parameter Values 
class ParameterValueClass { 
   double _Value; 
   double _Max; 
   public double Value { get { return (_Value < _Max) ? _Value : _Max }
                         set  { _Value = value; } } 
   public ParameterValueClass(Max) { _Max = Max; } 
 } 
// Set of Parameter Values 
class ParameterSetClass { 
      public ParameterValueClass Parameter1;
      public ParameterValueClass Parameter2;
      public ParameterValueClass Parameter3;
      public ParameterSetClass () { 
          Parameter1 = new ParameterValueClass(20);
          Parameter2 = new ParameterValueClass(4.22314);
          Parameter3 = new ParameterValueClass(700000);
      }
 } 

void ExampleMethod(ParameterSetClass Parameters) {
    /// Parameter1.Value returns the Value or "Max" value. Could also use a min value. 

  }

You can always use a reflection. This sample code in parameters collection contains a list of parameters that has default value. Each of this parameters has property DefaultValue with its default value.

private void Calc(int i, int j, int k = 60, int l = 80)
    {
        var parameters =
            System.Reflection.MethodInfo.GetCurrentMethod().GetParameters().Where(param => param.HasDefaultValue);
      //parameters = {k, l}

    }

You can create a method that just doing the term check and asigning the correct value you want to use to the var. (against the default value). Then, after having you 6-7 checked vars, invoke the method and provide those vars.

By your last statement, I'm assuming that you want the parameter to have the value you're actually going to use when you enter ExampleMethod(). One thing you might try is to create another object or static method that will calculate that value for you.

class Helper {
    public static int MakeParam(int myParam) {
      return myParam < 20 ? myParam : use_your_default_value_as_specified;
    }
}
...
ExampleMethod(Helper.MakeParam(17));

This allows you to do any logic on the parameter external to the method. If you need it, you could even have a version that allows you to pass in your default value:

class Helper {
    public static int MakeParam(int myParam) {
      return MakeParam(myParam, use_your_default_value_as_specified);
    }
    public static int MakeParam(int myParam, int myDefault) {
      return myParam < 20 ? myParam : myDefault;
    }
}

Then you can use named parameters to provide values for only the ones you want to use:

void Main()
{
    Console.WriteLine(AddEm(parm3:50)); // = 80
    Console.WriteLine(AddEm(parm2:50)); // = 90
    Console.WriteLine(AddEm());         // = 60)
}

public int AddEm(int parm1 = 10, int parm2 = 20, int parm3 = 30) {
    return parm1 + parm2 + parm3;
}

Good luck!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top