Difference between ParameterInfo.IsOptional and ParameterInfo.HasDefaultValue?

1.4k views Asked by At

They both sound similar. From msdn:

ParameterInfo.IsOptional

Gets a value indicating whether this parameter is optional.

This method depends on an optional metadata flag. This flag can be inserted by compilers, but the compilers are not obligated to do so.

This method utilizes the Optional flag of the ParameterAttributes enumerator.

ParameterInfo.HasDefaultValue (new in .NET 4.5)

Gets a value that indicates whether this parameter has a default value.

Aren't they the same? I did quick test:

public void A(string value)
{

}
public void B(string value, int i = -1)
{

}

I wrote:

var a = AInfo.GetParameters().Select(p => p.HasDefaultValue).ToArray();
var b = AInfo.GetParameters().Select(p => p.IsOptional).ToArray();

var c = BInfo.GetParameters().Select(p => p.HasDefaultValue).ToArray();
var d = BInfo.GetParameters().Select(p => p.IsOptional).ToArray();

//a equals b; and c equals d

So in which context are they different? Why did BCL introduce HasDefaultValue in .NET 4.5 newly?

3

There are 3 answers

8
Vyacheslav Volkov On BEST ANSWER

If we look at the implementation of IsOptional we will see:

public bool IsOptional
{
  [__DynamicallyInvokable] get
  {
    return (this.Attributes & ParameterAttributes.Optional) != ParameterAttributes.None;
  }
}

It depends on a metadata flag, but as it is written in the msdn:

This method depends on an optional metadata flag. This flag can be inserted by compilers, but the compilers are not obligated to do so.

This means that it depends on the compiler and if we use other compiler, we can get that parameter that has default value will not have IsOptional flag. Now let's see how HasDefaultValue property implemented:

public override bool HasDefaultValue
{
  get
  {
    if (this.m_noMetadata || this.m_noDefaultValue)
      return false;
    else
      return this.GetDefaultValueInternal(false) != DBNull.Value;
  }
}

It always checks whether the parameter has default value and does not depend on the compiler. This may not be a 100% correct answer, just my thoughts.

UPDATE 0

Here's example where parameter has not default value but IsOptional is true:

public static void Method([Optional]string parameter)
{
}

ParameterInfo parameterInfo = typeof(Program).GetMethod("Method").GetParameters()[0];
//Is true
bool isOptional = parameterInfo.IsOptional;
//Is false
bool hasDefaultValue = parameterInfo.HasDefaultValue;
1
Cheng Chen On

You can't get the conclusion "they are the same" using "a equals b; and c equals d", like:

int[] a = new[] { 0, 1, 5 };
var c = a.Where(n => n < 2).ToArray();
var d = a.Where(n => n < 3).ToArray();  
//you can't say "2 == 3" even c equals to d in sequence

Ok back to the topic, currently an optional parameter always has a default value, this conclusion is correct "by now". But AFAIK it's undocumented behavior, which means the compiler may change its behavior/implementation to optional parameters. So if you want to check(via reflection) if the parameter is an optional one, use .IsOptional property. If you want to check if it has a default value(maybe marked by some attribute e.g. DefaultValue? just maybe), use .HasDefaultValue property. Sounds like superfluous words but it's true.

0
nawfal On

Danny Chen and vvs0205 state the difference exactly, that IsOptional is always compiler dependent and to check if the parameter is an optional parameter whose default value is specified use HasDefaultValue.

bool isOptional = parameterInfo.IsOptional;

bool isOptionalWithADefaultValue = parameterInfo.HasDefaultValue; //.NET 4.5

bool isOptionalWithADefaultValue = (p.Attributes & ParameterAttributes.HasDefault) == ParameterAttributes.HasDefault; //.NET 4 and below

Taken from here (catch some other undocumented techniques to get the same in that thread)