Как компилятор поддерживает порядок, в котором будет вызван метод? [Дубликат]

Исправить исключение 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.

Для получения дополнительной информации: Операторы с нулевым условием

20
задан Dean Harding 9 September 2010 в 09:08
поделиться

5 ответов

Ответ указан в разделе C # раздела 7.3 и в разделе 7.5.5.1

Я сломал шаги, используемые для выбора метода для вызова .

  • Сначала создается множество всех доступных элементов с именем N (N=Foo), объявленных в T (T=class D) и базовых типов T (class C). Объявления, содержащие модификатор переопределения, исключаются из набора ( D.Foo (B) is exclude )
    S = { C.Foo(B) ; D.Foo(A) }
    
  • Создан набор методов-кандидатов для вызова метода. Начиная с набора методов, связанных с M, которые были найдены при поиске предыдущего элемента, набор сводится к тем методам, которые применимы относительно списка аргументов AL (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

Если абстрактный метод удаляется из C, исходный набор равен S = { D.Foo(B) ; D.Foo(A) }, а правило разрешения перегрузки должно использоваться для выбора лучший член функции в этом наборе.

В этом случае победителем является D.Foo(B).

13
ответ дан Julien Hoarau 26 August 2018 в 04:03
поделиться

Почему компилятор выбирает версию, которая принимает A, когда B является более производным классом?

Как отмечали другие, компилятор делает это, потому что это то, что говорит спецификация языка.

Это может быть неудовлетворительный ответ. Естественным продолжением было бы «какие принципы дизайна несут в себе решение указать язык таким образом?»

Это часто задаваемый вопрос, как в 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/

Вот мой ответ на тот же вопрос с прошлой недели, который выглядит замечательно, как этот.

Почему сигнатуры, объявленные в базовом классе, игнорируются?

И вот еще три актуальных или дублированных вопроса:

C # перегрузка разрешения?

Метод перегружает разрешение и мозговые тизеры Джона Скита

Почему это работает? Перегрузка метода + переопределение метода + полиморфизм

9
ответ дан Community 26 August 2018 в 04:03
поделиться

Итак, вот как это должно работать в соответствии со спецификацией (во время компиляции и при условии правильной навигации по документам):

Компилятор идентифицирует список методы сопоставления из типа 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, удаляются из набора.

Это по существу означает, что если есть применимый метод, объявленный в D, любые методы из базовые классы будут удалены из списка. На этом этапе у нас есть победитель:

D.Foo(A) (public)
1
ответ дан Fredrik Mörk 26 August 2018 в 04:03
поделиться

Я думаю, что при реализации другого класса он выглядит намного до дерева, чтобы получить надежную реализацию метода. Поскольку нет метода, называемого, он использует базовый класс. [f1]

, что догадка я не про в .Net

0
ответ дан Kieran 26 August 2018 в 04:03
поделиться

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

У вас есть метод Foo, который не является виртуальным и поэтому этот метод вызывается.

Эта ссылка имеет очень хорошее объяснение http://msdn.microsoft.com/en-us/library/aa645767%28VS.71%29.aspx

1
ответ дан Unmesh Kondolikar 26 August 2018 в 04:03
поделиться
Другие вопросы по тегам:

Похожие вопросы: