Частичные методы в пользовательских модулях Orchard

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

Однако во время выполнения мы получаем исключение, что разделяемый метод не реализован.

A first chance exception of type 'Microsoft.CSharp.RuntimeBinder.RuntimeBinderException' occurred in Microsoft.CSharp.dll

Additional information: 'MyModule.Drivers.CompanyPartDriver' does not contain a definition for 'CustomEditorGet'

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

Рассматриваемый бит выглядит следующим образом:

public partial class CompanyPartDriver : ContentPartDriver<CompanyPart>
{
   // other code

   partial void CustomEditorGet(CompanyPart part, dynamic shapeHelper, ref DriverResult result);

   protected override DriverResult Editor(CompanyPart part, dynamic shapeHelper)
   {
      DriverResult result;

      if (AdminFilter.IsApplied(HttpContext.Current.Request.RequestContext))
         result = ContentShape("Parts_CompanyAdmin_Edit",
                               () => shapeHelper.EditorTemplate(TemplateName: "Parts/CompanyAdmin",
                                                                Model: part,
                                                                Prefix: Prefix));
      else
         result = ContentShape("Parts_Company_Edit",
                               () => shapeHelper.EditorTemplate(TemplateName: "Parts/Company",
                                                                Model: part,
                                                                Prefix: Prefix));


      CustomEditorGet(part, shapeHelper, ref result);

      return result;
   }

   // other code
}

Добавление реализации метода «CustomEditorGet» в разделяемый класс в другом файле, даже если он пустой, все в порядке. Простое добавление частичного класса без частичного метода impl не исправит это.

Какие-нибудь мысли?


person Michael Sawczyn    schedule 20.08.2014    source источник
comment
Вы не даете полную трассировку стека исключения. Вы уверены, что показываете здесь все, что нужно? Имейте в виду, что если никакая часть partial class фактически не обеспечивает реализацию метода partial void, этот метод считается несуществующим во время компиляции. Так что на самом деле он не переводится в IL, и все вызовы к нему удаляются. Однако это не объясняет проблему, которую вы видите, поэтому я думаю, что мне нужно больше информации. Можете ли вы воспроизвести с помощью полного и автономного примера кода?   -  person Jeppe Stig Nielsen    schedule 21.08.2014
comment
Ах, извините, я не заметил, что вы использовали аргумент типа dynamic в своем вызове. В этом случае привязка откладывается до времени выполнения. Но метод partial void фактически не будет существовать во время выполнения.   -  person Jeppe Stig Nielsen    schedule 21.08.2014


Ответы (2)


(Надеюсь, кто-то захочет дать более точный ответ.)

Похоже, вы столкнулись с "плохим" коктейлем из разделяемых методов и dynamic аргументов.

С методом partial void, где никакая "часть" partial class не обеспечивает реализацию, метод partial void считается "несуществующим" во время компиляции и фактически не реализован в IL.

При вызове CustomEditorGet(part, shapeHelper, ref result);, где вторым аргументом является выражение типа dynamic времени компиляции, мы "привязываемся" к несуществующему методу. Обычно, когда dynamic не используется, весь этот вызов/вызов "удаляется" во время компиляции. Но поскольку это выражение dynamic, мы должны отложить "привязку" до времени выполнения. «Может быть, shapeHelper окажется очень «счастливым» типом, который действительно найдет метод CustomEditorGet для вызова?» Таким образом, вы получаете исключение во время выполнения.

person Jeppe Stig Nielsen    schedule 20.08.2014
comment
Крысы. Таким образом, в этой ситуации нельзя использовать частичные методы, чтобы программисты могли внедрять пользовательские функции в сгенерированный код. Возможно, мне придется переключиться на статические события, установленные в статическом конструкторе, хотя это кажется менее элегантным, чем частичные методы. Спасибо за помощь в разъяснении. (О, и я бы проголосовал, если бы у меня было достаточно очков для этого ... пока нет!) - person Michael Sawczyn; 21.08.2014

Мне это кажется неправильным использованием частичных классов, когда правильная конструкция является абстрактным методом. Гораздо более СУХОЙ.

person Bertrand Le Roy    schedule 21.08.2014
comment
Не могли бы вы уточнить? Вы предлагаете, чтобы сгенерированный код был базовым классом для конечного класса части, где затем был бы реализован абстрактный метод? Или мы должны сгенерировать часть и потребовать от программиста извлечь из нее и реализовать абстрактные методы? - person Michael Sawczyn; 21.08.2014
comment
В любом случае программисту придется проделать больше работы, чем я хочу, для основного случая использования, когда не требуются никакие изменения, поскольку абстрактный метод должен быть реализован, хотя реализация будет пустой, поскольку программист не не нужно ничего переопределять. Кроме того, не могли бы вы уточнить, где вы видите повторение? Конечно, сгенерированный код повторяется, но это сгенерированный код — я не ожидаю, что он будет СУХИМ. Спасибо. - person Michael Sawczyn; 21.08.2014
comment
Нет: генерировать базовый класс было бы глупо. Первый вопрос, который нужно задать, — зачем вы генерируете код. Сгенерированный код по-прежнему нуждается в управлении и имеет множество недостатков. Частичное нагромождение собственных проблем. Не говоря уже о том, что он нигде в Орчарде не используется. Я думаю, у вас должен быть базовый класс, но общий, а не сгенерированный. Производные классы могут реализовывать варианты. Если некоторые из этих реализаций должны быть пустыми, просто создайте пустую реализацию в базовом классе и сделайте ее виртуальной, а не абстрактной. - person Bertrand Le Roy; 22.08.2014