ParameterInfo.IsOptional和ParameterInfo.HasDefaultValue之间的区别是什么?

16

它们两个听起来很相似。来自于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

那么它们有什么不同的上下文呢?为什么BCL在.NET 4.5中新引入了HasDefaultValue


请给我点踩的人,如果我的问题很愚蠢,请把它作为答案,或者留下评论,这样我就可以更好地提问。 - nawfal
你是在说 PropertyInfo(属性信息)还是 ParameterInfo(参数信息)? - Marc Gravell
3个回答

8

如果我们看一下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;

是的,HasDefaultValue 是正确的做法,但在 .NET 4 中,你也可以使用 p.Attributes & ParameterAttributes.HasDefault 的方式。 - nawfal
ParameterAttributes.HasDefault 也取决于编译器。 - Vyacheslav Volkov
1
“这句话的意思是什么:“It is not 100% correct answer is just my thoughts.”?” - nawfal
你问为什么他们这样做?我不能确定地回答为什么他们这样做,我只能做出假设。 - Vyacheslav Volkov
啊,现在我明白了,但是你的措辞不太清楚。请查看我的修改。 - nawfal
显示剩余3条评论

3
丹尼·陈(Danny Chen)和vvs0205明确指出,IsOptional始终取决于编译器,要检查参数是否为可选参数,其默认值已指定,请使用HasDefaultValue
bool isOptional = parameterInfo.IsOptional;

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

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

从这里获取在那个帖子中,还有其他未记录的技巧可以实现相同效果


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

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


我明白了,我知道2 == 3不可能从中得出,当然 :)(我忽略了它)。这就是为什么我把它变成了一个问题。我只是陈述了一个场景,我可以想象HasDefaultValue可能与IsOptional不同,但并没有证明它确实如此。因此,我向社区提问,因为它听起来并不像一个基本的2 != 3那么确定。 - nawfal

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接