Примечание: ответ ниже был написан в 2010 году, задолго до того, как в C # 6 был введен оператор null условный .
Звучит так, будто вы ищете что-то вроде нулевого безопасного оператора разыменования Groovy, который позволял бы вам писать if (School?.ClassRoom?.Pupil?.Age != null)
- но C # не имел такого до C # 6.
Боюсь, что у вас есть для проверки каждого свойства на недействительность, при условии, что оно может быть null:
if (School != null && School.ClassRoom != null && School.ClassRoom.Pupil != null
&& School.ClassRoom.Pupil.Age != null)
{
MyMethod(School.ClassRoom.Pupil.Age);
}
Конечно, вы можете поместить весь этот блок if
, включая сам вызов метода, в вспомогательный метод и просто вызвать его.
Предполагается, что для каждого свойства будет null для начала. Если вы можете спроектировать свои классы так, чтобы нулевые значения даже не допускались - и вы проверяете это в конструкторах и т. Д. - ваш код, вероятно, окажется намного чище.
Стоит отметить, что здесь есть два альтернативных подхода - один, предложенный Крисом в другом ответе, заключается в создании объекта «по умолчанию» для каждого свойства; Я обычно нахожу, что лучше всегда требовать, чтобы в конструкторе было указано "реальное" значение. Объекты по умолчанию без реальных данных могут в конечном итоге привести к ошибкам, которые труднее отследить, чем NullReferenceException
проблем, поскольку вы можете долго и долго соглашаться с «фиктивными» данными и просто получить неверный результат в конце. Однако определенно бывают случаи, когда является правильным решением, особенно когда речь идет о коллекциях. Это зависит от ситуации.
РЕДАКТИРОВАТЬ: Саид предложил метод расширения в комментариях. Я предполагаю, что это будет что-то вроде:
public static int? PupilAgeOrNull(this School school)
{
return school != null &&
school.ClassRoom != null &&
school.ClassRoom.Pupil != null
? school.ClassRoom.Pupil.Age : null;
}
(Отрегулируйте для типов соответствующим образом.)
Я определенно предпочитаю идею пытаться сохранить вещи ненулевыми в другом месте, но это будет делать, если вам это нужно. Мне кажется, что это неправильно. В основе этого интуитивного ощущения лежит тот факт, что вы начинаете навигацию по трем или четырем свойствам - для меня это выглядит как нарушение Закона Деметры . Теперь я не из тех, кто догматично относится к таким вещам, но использование метода расширения для School
кажется мне слишком специфичным для такого длинного пути свойств.
Другая альтернатива, которая также несколько неприятна, IMO, - написать три различных метода расширения:
public static ClassRoom ClassRoomOrNull(this School school)
{
return school == null ? null : school.ClassRoom;
}
public static Pupil PupilOrNull(this ClassRoom classRoom)
{
return classRoom == null ? null : classRoom.Pupil;
}
public static int? AgeOrNull(this Pupil pupil)
{
return pupil == null ? null : pupil.Age;
}
Тогда вы можете написать:
int? age = School.ClassRoomOrNull().PupilOrNull().AgeOrNull();
if (age != null)
{
MyMethod(age);
}
Это означает, что метод расширения в School
не столь специфичен. У вас все еще есть длинная цепочка вызовов методов, и я все же попытался бы изменить дизайн, чтобы избежать этой ситуации, если это возможно, но, по крайней мере, нет такой тесной связи с School
до School.ClassRoom.Pupil.Age
.