14

它们听起来很相似。来自 msdn:

ParameterInfo.IsOptional

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

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

此方法利用 ParameterAttributes 枚举器的 Optional 标志。

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

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

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

public void A(string value)
{

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

}

我写:

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

那么它们在哪些情况下不同呢?为什么HasDefaultValue在.NET 4.5 中新引入了BCL?

4

3 回答 3

7

如果我们看一下实现,IsOptional我们会看到:

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

它取决于元数据标志,但正如它在 msdn 中所写的那样:

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

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

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

它始终检查参数是否具有默认值,并且不依赖于编译器。这可能不是一个 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;
于 2013-04-24T09:03:20.093 回答
3

Danny Chen 和 vvs0205 准确地说明了区别,即IsOptional始终依赖于编译器,并检查参数是否是指定默认值的可选参数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

取自这里捕捉其他一些未记录的技术以在该线程中获得相同

于 2013-04-24T10:58:12.707 回答
1

您无法使用“a 等于 b;c 等于 d”得出“它们相同”的结论,例如:

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

好的,回到主题,目前可选参数总是有一个默认值,这个结论“现在”是正确的。但是 AFAIK 它是未记录的行为,这意味着编译器可能会将其行为/实现更改为可选参数。因此,如果您想检查(通过反射)参数是否是可选参数,请使用.IsOptional属性。如果您想检查它是否具有默认值(可能由某些属性标记,例如 DefaultValue?只是可能),请使用.HasDefaultValue属性。听起来像是多余的话,但这是真的。

于 2013-04-24T08:32:47.523 回答