Это известная проблема. Вот несколько ссылок, связанных с ним:
Я также проверил ваш сценарий, используя C# 7.3 (.NET 4.7.2)
и C# 8 (.NET Core 3.1)
, и проблема все еще существует. Поэтому, если вы используете инициализатор объекта и одно из значений инициализатора выдает исключение, то из трассировки стека невозможно узнать, какое из значений инициализатора вызвало исключение.
Обходной путь
Давайте рассмотрим следующий класс Person
:
class Person
{
public string Name { get; set; }
public DateTime DateOfBirth { get; set; }
public int Age { get; set; }
}
и предположим, что экземпляр класса Person
создается с использованием следующего кода:
// Return type of the methods getName(), getDateOfBirth() and getAge() is object.
// Each of this methods can return invalid value, for example, method getAge()
// can return string value causing InvalidCastException.
Person p = new Person
{
Name = (string) getName(),
DateOfBirth = (DateTime) getDateOfBirth(),
Age = (int) getAge()
};
Если одно из значений инициализатора (например, приведение результата метода getName()
к string
типу данных) выдает исключение, мы не сможем узнать, какое из значений инициализатора является причина исключения, потому что номер строки в трассировке стека будет указывать на строку Person p = new Person
.
Чтобы обойти эту проблему, мы можем отказаться от использования инициализатора объекта и использовать инициализацию объекта старого стиля:
Person p = new Person();
p.Name = (string) getName();
p.DateOfBirth = (DateTime) getDateOfBirth();
p.Age = (int) getAge();
Теперь, если возникнет исключение, мы сможем узнать точный номер строки, где произошло исключение.
Здесь мы должны выбрать между чтением способность (инициализатор объекта) и возможность получения более точной информации о причине исключений при инициализации.
Есть и другие обходные пути. Например, мы можем проверить значения инициализатора перед его использованием в инициализаторе объекта:
Заключение
Это известная проблема. Это все еще существует и не исправлено. Мы можем обойти это, отказавшись от использования инициализаторов объектов и установщиков свойств (p.Name = (string) getName()
). Также могут быть использованы другие обходные пути (например, проверка значений инициализатора перед использованием инициализатора объекта).
Мы должны осторожно использовать инициализаторы объекта. Если значения инициализатора могут вызвать исключение, мы должны рассмотреть инициализацию объекта с использованием установщиков свойств (p.Name = (string) getName()
), потому что это упростит отладку в будущем.