Почему наклон частичные методы быть общедоступным, если реализация находится в том же блоке?

Согласно Документации MSDN для частичных классов:

Частичные методы неявно закрыты

Таким образом, у Вас может быть это

// Definition in file1.cs
partial void Method1();

// Implementation in file2.cs
partial void Method1()
{
  // method body
}

Но у Вас не может быть этого

// Definition in file1.cs
public partial void Method1();

// Implementation in file2.cs
public partial void Method1()
{
  // method body
}

Но почему это? Действительно ли там некоторой причиной является компилятор, не может обработать общедоступные частичные методы?

17
задан Naser Asadi 20 August 2014 в 10:26
поделиться

7 ответов

Потому что у группы компиляторов MS не было требования реализовать эту функцию.

Вот возможный сценарий того, что происходит внутри MS, поскольку VS использует генерацию кода для многих своих функций, однажды разработчик генерации кода MS решил, что ему / ей нужны частичные методы, чтобы сгенерированный код api мог быть расширенным посторонними, и это требование побудило команду компиляторов действовать и выполнять.

6
ответ дан 30 November 2019 в 10:46
поделиться

Не уверен, что это ответ на ваш вопрос, он ответил на мой. Частичные методы

Отрывки:

Если вам разрешили что-то вернуть, и, в свою очередь, использовали это как возвращаемое значение из вашего CallMyMethods функция, вы столкнетесь с проблемами когда частичные методы не были реализовано.

0
ответ дан 30 November 2019 в 10:46
поделиться

Если вы не определите метод, что должен делать компилятор?

Если вы не определите их, частичные методы не будут компилироваться вообще .
Это возможно только потому, что компилятор знает, где находятся все вызовы метода. Если метод не определен, он полностью удалит строки кода, вызывающие метод. (Вот почему они могут возвращать только void )

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

3
ответ дан 30 November 2019 в 10:46
поделиться

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

Когда вы добавляете метод в свой публичный API - вы определяете контракт для других объектов. Так как вся суть частичного метода заключается в том, чтобы сделать его необязательным, вы, по сути, говорите: "У меня есть контракт, на который вы можете положиться". Подождите, вы не можете полагаться на этот метод"

Для того, чтобы публичный API был разумным, частичный метод должен действительно либо всегда быть там, либо всегда отсутствовать - и в этом случае он не должен быть частичным.

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

27
ответ дан 30 November 2019 в 10:46
поделиться

Вместо того, чтобы спрашивать , почему они частные , давайте перефразируем вопрос следующим образом:

  • Что бы произошло, если бы частичные методы не были private?

Рассмотрим этот простой пример:

public partial class Calculator
{
    public int Divide(int dividend, int divisor)
    {
        try
        {
            return dividend / divisor;
        }
        catch (DivideByZeroException ex)
        {
            HandleException(ex);
            return 0;
        }
    }

    partial void HandleException(ArithmeticException ex);
}

Давайте пока проигнорируем вопрос, почему мы должны сделать этот метод частичным, а не абстрактным (я вернусь к этому). Важно то, что это компилируется - и работает правильно - независимо от того, реализован ли метод HandleException или нет. Если его никто не реализует, это просто поглощает исключение и возвращает 0.

Теперь давайте изменим правила, скажем, что частичный метод может быть защищен:

public partial class Calculator
{
    // Snip other methods

    // Invalid code
    partial protected virtual void HandleException(ArithmeticException ex);
}

public class LoggingCalculator : Calculator
{
    protected override virtual void HandleException(ArithmeticException ex)
    {
        LogException(ex);
        base.HandleException(ex);
    }

    private void LogException(ArithmeticException ex) { ... }
}

У нас здесь небольшая проблема. Мы «переопределили» метод HandleException , за исключением того, что его еще нет. И я имею в виду, что метод буквально не существует , он вообще не компилируется.

Что означает, что наш базовый калькулятор вызывает HandleException ? Должен ли он вызывать производный (переопределенный) метод? Если да, то какой код генерирует компилятор для базового метода HandleException ? Следует ли превратить его в абстрактный метод? Пустой метод? А что происходит, когда производный метод вызывает base.HandleException ? Это должно просто ничего не делать? Вызвать исключение MethodNotFoundException ? Здесь действительно сложно следовать принципу наименьшего удивления; почти все, что вы делаете, вас удивит.

Или, может быть, ничего не должно произойти при вызове HandleException , потому что базовый метод не был реализован. Однако это не кажется интуитивно понятным. Наш производный класс реализовал этот метод, а базовый класс вытащил ковер из-под себя без нашего ведома. Я легко могу представить, как какой-то плохой разработчик вырывает себе волосы, не в силах понять, почему его переопределенный метод никогда не выполняется.

Или, может быть, этот код вообще не должен компилироваться или должен выдавать предупреждение. Но здесь есть ряд проблем. Что наиболее важно, он нарушает контракт, предоставляемый частичными методами, в котором говорится, что пренебрежение его реализацией никогда не должно приводить к ошибке компилятора. У вас есть базовый класс, который прекрасно работает, а затем, в силу того факта, что кто-то реализовал полностью допустимый производный класс в какой-то совершенно другой части приложения , ваше приложение внезапно выходит из строя.

И я даже не начал говорить о возможности нахождения базового и производного классов в разных сборках. Что произойдет, если вы ссылаетесь на сборку с базовым классом, содержащим «общедоступный» частичный метод, и пытаетесь переопределить его в производном классе в другой сборке? Есть базовый метод или нет? Что, если изначально метод был реализован, и мы написали кучу кода против него, но кто-то решил удалить реализацию? У компилятора нет способа заглушить частичные вызовы методов из ссылающихся классов, потому что, что касается компилятора, этот метод никогда не существовал изначально . Его там нет, его больше нет в IL скомпилированной сборки. Итак, теперь, просто удалив реализацию частичного метода, который не должен иметь вредных последствий, мы взломали целую кучу зависимого кода.

Некоторые люди могут сказать: «Ну и что, я знаю, что не собираюсь пытаться делать эти незаконные вещи частичными методами». Вы должны понимать, что частичные методы - как и частичные классы - в первую очередь предназначены для упрощения задачи генерации кода . Маловероятно, что вы когда-нибудь захотите написать частичный метод самостоятельно период . С другой стороны, с сгенерированным машиной кодом, на самом деле весьма вероятно, что потребители кода захотят «внедрить» код в различные места, а частичные методы обеспечивают чистый способ сделать это.

И в этом проблема.Если вы представите возможность ошибок времени компиляции из-за частичных методов, вы создадите ситуацию, в которой генератор кода генерирует код, который не компилируется . Это очень и очень плохая ситуация. Подумайте, что бы вы сделали, если бы ваш любимый дизайнерский инструмент - скажем, Linq to SQL, или конструктор Winforms или ASP.NET - внезапно начал создавать код, который иногда не компилируется,все потому, что какой-то другой программист создал какой-то другой класс, который вы никогда раньше не видели, который оказался слишком близок к частичному методу?

В конце концов, все сводится к гораздо более простому вопросу: что добавят ли общедоступные / защищенные частичные методы того, что вы уже не можете выполнить с помощью абстрактных методов? Идея партиалов заключается в том, что вы можете поместить их в конкретные классы, и они все равно будут компилироваться. Или, скорее, они не будут компилироваться, но и не выдадут ошибку, они просто будут полностью проигнорированы. Но если вы ожидаете, что они будут вызываться публично, тогда они больше не являются «необязательными», и если вы ожидаете, что они будут переопределены в производном классе, тогда вы можете просто сделать его абстрактным или виртуальным и пустым. На самом деле нет никакого использования для публичного или защищенного частичного метода, кроме как запутать компилятор и бедного ублюдка, пытающегося разобраться во всем этом.

Поэтому вместо того, чтобы открывать ящик Пандоры, команда сказала: забудьте об этом - публичные / защищенные частичные методы в любом случае мало пригодны, поэтому просто сделайте их приватными. Таким образом мы сможем сохранить все в безопасности и в здравом уме. И это. Пока частичные методы остаются закрытыми, они просты для понимания и не требуют беспокойства. Так и оставим!

8
ответ дан 30 November 2019 в 10:46
поделиться

Ответы Рида и Слака полностью верны, но вы, похоже, не желаете принимать их ответы.

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

Частичные методы предназначены для реализации определенных видов сценариев генерации кода с максимальной эффективностью, как с точки зрения времени выполнения, так и с точки зрения накладных расходов на метаданные. Последняя часть является реальной причиной для них, поскольку они пытаются их реализовать ( словами Эрикс) «Плати за игру».

Когда были добавлены частичные методы, JIT была полностью способна встраивать пустой метод и, таким образом, не требовала времени выполнения на сайтах вызова. Проблема в том, что даже в этом случае есть затраты, заключающиеся в том, что метаданные для класса будут иметь эти пустые методы, увеличивающие свой размер (без нужды), а также заставляющие дополнительные усилия во время процесса JITing для их оптимизации.

Хотя вы можете не слишком беспокоиться об этой стоимости (а многие люди даже не заметят ее), она имеет большое значение для кода, где стоимость запуска имеет значение или где диск / память ограничены. Вы, возможно, заметили, что сейчас обязательное использование .Net в Windows Mobile 7 и Zune, в этих областях раздувание метаданных типов обходится дорого.

Таким образом, частичные методы разработаны таким образом, что, если они никогда не используются, они имеют абсолютно нулевую стоимость, они перестают существовать на выходе каким-либо образом. Это связано с некоторыми существенными ограничениями, чтобы гарантировать, что это не приведет к ошибкам.

Взято со страницы msdn с моими заметками.

  • ... метод должен возвращать void.
  • Частичные методы могут иметь параметры ref, но не параметры out.

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

  • Частичные методы не могут быть внешними, потому что наличие тела определяет, являются ли они определяющими или реализующими.
  • Вы можете сделать делегатом частичный метод, который был определен и реализован, но не частичный метод, который был только определен.

Это следует из того факта, что компилятор должен знать, определен он или нет, и поэтому его можно безопасно удалить. Это приводит нас к тому, что вам не нравится.

  • Частичные методы неявно являются частными, поэтому они не могут быть виртуальными.

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

Если вы измените эту функцию, у вас будет два варианта:

  1. Принудительно установить для всех не частных частичных методов , требовать реализации .

    • простые и вряд ли потребуют больших усилий, но тогда любые такие методы больше не являются частичными в значимом смысле первоначального плана.
  2. Любой метод, объявленный как открытый, просто удаляется, если он не был реализован в сборке.

    • Это позволяет применить частичное удаление.
    • Это требует гораздо больше усилий со стороны компилятора (чтобы обнаружить все ссылки на метод, а не просто искать в самом составном классе)
    • Реализация IntelliSense немного запутался, стоит ли показать метод? сеется только тогда, когда ему дано определение?
    • Разрешение перегрузки становится намного более сложным, поскольку вам нужно решить, является ли вызов такого метода без определения либо а) ошибкой во время компиляции, или б) результатом выбора следующего наилучшего варианта, если он доступен.
    • Побочные эффекты в выражениях на сайтах вызова уже сложны в частном случае. Это несколько смягчается предположением, что частичные реализации уже демонстрируют высокую степень связи. Это изменение увеличит потенциал для сцепления.
    • Это имеет довольно сложные режимы отказа, так как общедоступные методы могут быть незаметно удалены некоторыми безобидными изменениями в исходной сборке. Другие сборки, зависящие от этого, завершатся ошибкой (во время компиляции), но с очень запутанной ошибкой (без значительных усилий это применимо даже к проектам в том же решении).

Решение 1 просто бессмысленно, оно требует дополнительных усилий и не приносит пользы исходным целям. Хуже того, это может фактически помешать первоначальным целям, поскольку кто-то, использующий частичные методы таким образом, может не осознавать, что они не получают сокращения метаданных. Также кто-то может запутаться в ошибках, возникающих из-за отсутствия определения.

Это оставляет нам решение 2.Это решение требует усилий (и каждая функция начинается с -100 ), поэтому оно должно добавить неоспоримое преимущество, чтобы получить его по сравнению с -100 (и дополнительные негативы, добавленные для путаницы, вызванной не дополнительными крайними случаями) . Какие сценарии вы можете придумать, чтобы добиться положительных результатов?

Ваш мотивирующий пример в комментариях выше заключался в том, чтобы «иметь комментарии / и / или атрибуты в другом файле»

Мотивация для комментариев XML было полностью увеличить локальность документации и кода.Если их многословность высока, существуют схемы для смягчения этого. Я считаю, что этого недостаточно, чтобы заслужить эту функцию.

Возможность перемещать атрибуты в отдельное место, на мой взгляд, не так уж и полезно, на самом деле я думаю, что необходимость смотреть в двух местах более запутанна. Текущая реализация, предназначенная только для частных, также имеет эту проблему, но она неизбежна и снова несколько смягчается предположением, что высокая степень связи, которая не видна вне класса, не так плоха, как высокая степень связи вне класса.

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

2
ответ дан 30 November 2019 в 10:46
поделиться

Простая причина состоит в том, что частичные методы не являются общедоступными, потому что они являются деталью реализации. Они предназначены в первую очередь для поддержки сценариев, связанных с дизайнером, и никогда не должны быть частью поддерживаемого общедоступного API. Непубличный метод здесь отлично работает.

Возможность делать частичные методы общедоступными - это особенность. Функции имеют неотъемлемую стоимость, включая проектирование, тестирование, разработку и т. Д.Частичные методы были лишь одной из многих функций, добавленных в очень упакованную Visual Studio 2008. Их область видимости была как можно меньше, чтобы соответствовать сценарию, чтобы оставить место для более важных функций, таких как LINQ.

0
ответ дан 30 November 2019 в 10:46
поделиться
Другие вопросы по тегам:

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