2010-11-21 3 views
2

В настоящее время я пытаюсь проверить, если ссылка является недействительным, прежде чем она используется «MyMethod» с:# C - «ссылка на объект не указывает на экземпляр объекта»

if (School.ClassRoom.Pupil.Age != null) 
     { 
      MyMethod(School.ClassRoom.Pupil.Age); 
     } 

Однако, я m по-прежнему получает ссылку «Ссылка на объект, не установленную на экземпляр объекта» в первой строке, потому что не только значение null null, но также и Pupil и ClassRoom также имеют значение null.

У меня проблемы с использованием Try, Catch, Наконец, поскольку я получаю ту же ошибку в примере кода Try.

Я не хочу, чтобы каждый ClassRoom проверял значение null, а затем каждый Ученик для null, а затем каждый Возраст для нуля каждый раз, когда я хочу использовать этот метод.

Есть ли более простой способ сделать это?

+0

Как вы заполняете School.ClassRoom .. данные? Во время заполнения не разрешайте NULL-линии? –

+0

Btw, ваше название не подходит. Нет ничего путающего в том, какое исключение вы получаете. –

+0

Если возможно, я хотел бы иметь возможность продолжить использование нулевых классов, поскольку это часть довольно сложной структуры данных, и если я начну иметь новые экземпляры всех нулей, я думаю, что использование памяти будет проходить через крышу. – Caustix

ответ

5

Похоже, вы за чем-то вроде нулевого безопасного оператора разборки Groovy, который позволил бы вам написать if (School?.ClassRoom?.Pupil?.Age != null) - но у C# такого не бывает.

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

if (School != null && School.ClassRoom != null && School.ClassRoom.Pupil != null 
    && School.ClassRoom.Pupil.Age != null) 
{ 
    MyMethod(School.ClassRoom.Pupil.Age); 
} 

Конечно, вы могли бы поместить весь этот if блок, включающего в себя вызов метода в вспомогательный метод, и просто позвоните.

Предполагается, что он действителен для каждого объекта до be null для начала. Если вы можете создавать свои классы, чтобы нулевые значения даже не разрешались - и вы проверяете это в конструкторах и т. Д., Ваш код, скорее всего, станет намного более чистым.

Следует отметить, что здесь есть два альтернативных подхода: один, предложенный Крисом в другом ответе, заключается в создании объекта «по умолчанию» для каждого свойства; I обычно считают, что лучше всегда требовать «реального» значения, которое должно быть представлено в конструкторе. Объекты по умолчанию без реальных данных могут в конечном итоге вызвать ошибки, которые сложнее отслеживать, чем NullReferenceException проблемы, так как вы можете долго продолжать использовать «фиктивные» данные в течение длительного времени и просто получить неправильный результат в конце. Есть определенные моменты, когда Правильная вещь, которую нужно сделать, однако - особенно когда дело касается коллекций. Это зависит от ситуации.

EDIT: Саид предложил метод расширения в комментариях. Я полагаю, что это будет что-то вроде: (. Adjust для типов соответственно)

public static int? PupilAgeOrNull(this School school) 
{ 
    return school != null && 
      school.ClassRoom != null && 
      school.ClassRoom.Pupil != null 
      ? school.ClassRoom.Pupil.Age : null; 
} 

Я определенно предпочитаю идею пытаются держать вещи ненулевым в другом месте, но это будет делать, если вам это нужно , Мне это кажется неправильным. В основе этого чувства кишки лежит тот факт, что вы начинаете с трех или четырех свойств - это похоже на нарушение Law of Demeter для меня. Теперь я не из тех, кто догматичен по поводу таких вещей, но при этом метод расширения на 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.

+0

он не хочет этого делать, вместо 'if' пишет метод расширения –

+0

@Saeed: Um, где он упомянул методы расширения? –

+1

if (School.IsNullAge()) Легко написать такую ​​функцию, почему он должен упоминать об этом, он не любит уродливый код –

1

Дайте код, который вы указали, нет более простого способа. Вам нужно будет проверить каждый компонент.

if (School != null && School.ClassRoom != null 
    && School.ClassRoom.Pupil != null 
    && School.ClassRoom.Pupil.Age != null) 
{ 
    ... 
} 

Однако, вы можете написать свой код таким образом, чтобы члены никогда не null. Таким образом, вы можете избежать необходимости проверки на null. Например

class School 
{ 
    private ClassRoom _classRoom = new ClassRoom(); 

    public ClassRoom ClassRoom 
    { 
    get {return _classRoom;} 
    } 
} 

Это даст Общеобразовательная школа пустой класс комнату, чтобы начать с, так что это не null и не может быть установлен на внешней стороне null класса, так как собственность не имеет сеттера. Вы можете перенести эту концепцию вперед, ваш список учеников (я предполагаю, что это будет список) может быть пустым списком, а не нулевым экземпляром и т. Д.

1

«Нулевой шаблон объекта» приходит на помощь. Прочитано here.

Итак, у вас могут быть NullSchool, NullClassRoom, NullPupil, NullAge.

Тогда вам не нужно проверять наличие нулевой вещи, вместо этого у вас может быть только одна проверка (или метод, например IsValid() в Age class, конечно-виртуальный) в MyMethod, чтобы отклонить возраст, если он недействителен.

+0

Ну, это может * прийти на помощь. Это зависит от того, действительно ли существует * разумная «нулевая» версия. Как я писал в своем ответе, предоставление фиктивных данных может легко привести к затрудненным диагностике проблем. –

2

Here хорошее и элегантное решение с Expression Trees. Попробуйте и наслаждайтесь!

Смежные вопросы