Разница между ParameterInfo.IsOptional и ParameterInfo.HasDefaultValue?

Они оба звучат одинаково. Из MSDN:

ParameterInfo.IsOptional

Получает значение, указывающее, является ли этот параметр необязательным.

Этот метод зависит от необязательного флага метаданных. Этот флаг может быть вставлен компиляторами, но компиляторы не обязаны это делать.

Этот метод использует опциональный флаг перечислителя ParameterAttributes.

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 ввел HasDefaultValue в.NET 4.5 недавно?

3 ответа

Решение

Если мы посмотрим на реализацию 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 правда:

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;

Дэнни Чен и 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

Взято отсюда (воспользуйтесь другими недокументированными приемами, чтобы получить то же самое в этой теме)

Вы не можете получить заключение "они одинаковы", используя "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 имущество. Звучит как лишние слова, но это правда.

Другие вопросы по тегам