Исправить исключение NullReferenceException можно с помощью Null-условных операторов в c # 6 и написать меньше кода для обработки нулевых проверок.
Он используется для проверки нуля до выполнения доступа к члену (?. ) или index (? [).
Пример
var name = p?.Spouse?.FirstName;
эквивалентен:
if (p != null)
{
if (p.Spouse != null)
{
name = p.Spouse.FirstName;
}
}
В результате имя будет нулевым когда p равно null или когда p.Spouse имеет значение null.
В противном случае имени переменной будет присвоено значение p.Spouse.FirstName.
Для получения дополнительной информации: Операторы с нулевым условием
Ответ указан в разделе C # раздела 7.3 и в разделе 7.5.5.1
Я сломал шаги, используемые для выбора метода для вызова .
N=Foo
), объявленных в T (T=class D
) и базовых типов T (class C
). Объявления, содержащие модификатор переопределения, исключаются из набора ( D.Foo (B) is exclude ) S = { C.Foo(B) ; D.Foo(A) }
AL=B
). Сложная редукция состоит из применения следующих правил к каждому методу TN в множестве, где T (T=class D
) - тип, в котором объявлен метод N (N=Foo
): если N не применимо относительно AL ( Раздел 7.4.2.1 ), тогда N удаляется из набора. C.Foo(B)
применимо в отношении AL D.Foo(A)
применимо относительно AL S = { C.Foo(B) ; D.Foo(A) }
. Если N применимо относительно AL (раздел 7.4.2.1), то все методы, объявленные в базовом типе T, удаляются из задавать. C.Foo(B)
удаляется из набора S = { D.Foo(A) }
. В конце победителем является D.Foo(A)
.
Если абстрактный метод удаляется из C, исходный набор равен S = { D.Foo(B) ; D.Foo(A) }
, а правило разрешения перегрузки должно использоваться для выбора лучший член функции в этом наборе.
В этом случае победителем является D.Foo(B)
.
Почему компилятор выбирает версию, которая принимает A, когда B является более производным классом?
blockquote>Как отмечали другие, компилятор делает это, потому что это то, что говорит спецификация языка.
Это может быть неудовлетворительный ответ. Естественным продолжением было бы «какие принципы дизайна несут в себе решение указать язык таким образом?»
Это часто задаваемый вопрос, как в StackOverflow, так и в моем почтовом ящике. Краткий ответ: «Этот проект смягчает семейство ошибок класса Brittle Base Class».
Описание функции и ее описание так, как показано в моей статье на эту тему:
http://blogs.msdn.com/ b / ericlippert / archive / 2007/09/04 / future-break-changes-part-three.aspx
Дополнительные статьи о том, как различные языки относятся к базовому классу Brittle Base проблема см. в моем архиве статей по теме:
http://blogs.msdn.com/b/ericlippert/archive/tags/brittle+base+classes/
Вот мой ответ на тот же вопрос с прошлой недели, который выглядит замечательно, как этот.
Почему сигнатуры, объявленные в базовом классе, игнорируются?
И вот еще три актуальных или дублированных вопроса:
Метод перегружает разрешение и мозговые тизеры Джона Скита
Почему это работает? Перегрузка метода + переопределение метода + полиморфизм
Итак, вот как это должно работать в соответствии со спецификацией (во время компиляции и при условии правильной навигации по документам):
Компилятор идентифицирует список методы сопоставления из типа D
и его базовых типов, основанные на имени метода и списке аргументов. Это означает, что любой метод с именем Foo
, принимающий один параметр типа, для которого существует неявное преобразование из B
, является допустимым кандидатом. Это приведет к следующему списку:
C.Foo(B) (public virtual)
D.Foo(B) (public override)
D.Foo(A) (public)
Из этого списка исключаются любые объявления, содержащие модификатор переопределения. Это означает, что список теперь содержит следующие методы:
C.Foo(B) (public virtual)
D.Foo(A) (public)
. В этот момент у нас есть список подходящих кандидатов, и теперь компилятор должен решить, что вызывать. В документе 7.5.5.1 Вызов метода мы находим следующий текст:
Если N применимо относительно A (). Раздел 7.4.2.1 ), то все методы, объявленные в базовом типе T, удаляются из набора.
blockquote>Это по существу означает, что если есть применимый метод, объявленный в
D
, любые методы из базовые классы будут удалены из списка. На этом этапе у нас есть победитель:D.Foo(A) (public)
Я думаю, что при реализации другого класса он выглядит намного до дерева, чтобы получить надежную реализацию метода. Поскольку нет метода, называемого, он использует базовый класс. [f1]
, что догадка я не про в .Net
Я думаю, что это связано с тем, что в случае не виртуального метода используется тип времени компиляции переменной, в которой вызывается метод.
У вас есть метод Foo, который не является виртуальным и поэтому этот метод вызывается.
Эта ссылка имеет очень хорошее объяснение http://msdn.microsoft.com/en-us/library/aa645767%28VS.71%29.aspx