ParameterInfo.IsOptional和ParameterInfo.HasDefaultValue之间的区别?

naw*_*fal 11 .net reflection default-value optional-parameters parameterinfo

它们听起来都很相似.来自msdn:

ParameterInfo.IsOptional

获取一个值,该值指示此参数是否可选.

此方法取决于可选的元数据标志.编译器可以插入此标志,但编译器没有义务这样做.

此方法使用ParameterAttributes枚举器的Optional标志.

ParameterInfo.HasDefaultValue(.NET 4.5中的新增功能)

获取一个值,该值指示此参数是否具有默认值.

他们不一样吗?我做了快速测试:

public void A(string value)
{

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

}
Run Code Online (Sandbox Code Playgroud)

我写:

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
Run Code Online (Sandbox Code Playgroud)

那么它们在哪种情况下有所不同?为什么BCL HasDefaultValue新推出.NET 4.5?

Vya*_*kov 6

如果我们看一下实施情况,IsOptional我们会看到:

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

它取决于元数据标志,但它是在msdn中编写的:

此方法取决于可选的元数据标志.编译器可以插入此标志,但编译器没有义务这样做.

这意味着它依赖于编译器,如果我们使用其他编译器,我们可以获得具有默认值的参数将不具有IsOptional标志.现在让我们看看HasDefaultValue属性是如何实现的:

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

它始终检查参数是否具有默认值,并且不依赖于编译器.这可能不是100%正确答案,只是我的想法.

更新0

这是参数没有默认值但是IsOptional为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;
Run Code Online (Sandbox Code Playgroud)