РЕДАКТИРОВАТЬ Я обрезал некоторые текущие комментарии здесь - просто просмотрите историю, чтобы увидеть.
Так что вы можете сделать эту работу с 1, 2, 3 или4 универсальных параметра кортежа, но они не работают с 5. Как только вы используете 5 параметров, он генерирует код, подобный следующему:
public class _Page_Views_Home_Index_cshtml :
System.Web.Mvc.WebViewPage<List<System.Tuple<string {
Я просто хотел выяснить, является ли это ограничение длины символа, поэтомуЯ сгенерировал класс, подобный этому:
namespace ASP{ //same namespace that the backend code for the page is generated
public class T { }
}
И изменил объявление модели:
@model List<Tuple<T,T,T,T,T>>.
В конце (см. Историю) я получил
@inherits System.Web.Mvc.WebViewPage<Tuple<T,T,T,T,T>>
Та же проблема!Это не проблема с ключевым словом @model ...
Это заняло некоторое время (чтение из источника MVC3 и Razor, добавление пары тестов к этому решению) - но вот тест, который показывает, почему мыполучите эту ошибку:
[TestMethod]
public void TestMethod()
{
System.CodeDom.CodeTypeReferenceCollection c =
new CodeDom.CodeTypeReferenceCollection();
c.Add("Tuple<T,T,T,T>");
c.Add("Tuple<T,T,T,T,T>");
//passes
Assert.AreEqual("Tuple<T,T,T,T>", c[0].BaseType);
//fails
Assert.AreEqual("Tuple<T,T,T,T,T>", c[1].BaseType);
}
Итак - версия с четырьмя параметрами проходит, но не версия с пятью параметрами.
И угадайте, какое фактическое значение составляет Tuple<T
- то есть усеченноеимя общего типа усекается точно так же, как вы видели в своем коде .
И стандартный синтаксический анализатор Razor, и синтаксический анализатор Mvc Razor используют тип CodeTypeReferenceCollection
при синтаксическом анализе @inherits
или @model
ключевое слово.Вот код для @inherits
во время генерации кода:
protected internal virtual void VisitSpan(InheritsSpan span) {
// Set the appropriate base type
GeneratedClass.BaseTypes.Clear();
GeneratedClass.BaseTypes.Add(span.BaseClass);
if (DesignTimeMode) {
WriteHelperVariable(span.Content, InheritsHelperName);
}
}
GeneratedClass.BaseTypes
является CodeTypeReferenceCollection
- и span.BaseClass
является строкой.После этого в ILSpy метод-нарушитель должен быть закрытым CodeTypeReference.Initialize(string typeName, CodeTypeReferenceOptions options)
.Сейчас у меня недостаточно времени, чтобы понять, почему это происходит, но я думаю, что это работа разработчика Microsoft :) Обновление ниже - не удержался.Теперь я знаю, где это неправильно
Итог
Вы не можете использовать дженерики с более чем 4 параметрами в выражениях Razor @inherits
или @model
(вменьше всего в C # - не знаю о VB).Похоже, что синтаксический анализатор Razor неправильно использует тип CodeTypeReference
.
Окончательное обновление - или у меня есть кусочек между зубами:)
Одна из вещей, которые CodeTypeReference
делаетэто вырезать информацию об имени сборки из переданного имени типа с помощью вызова метода CodeTypeReference.RipOffAssemblyInformationFromTypeName(string typeName)
.
И, конечно, если вы подумаете об этом - Tuple<T,T,T,T,T>
точно так же, как имя типа с учетом сборки:С именем типа = Tuple<T
, Assembly = T
, Version = T
, Culture = T
, PublicKeyToken = T
(если вы пишете действительно BAD C # парсер!).
Конечно же - если вы передадите Tuple<T,T,T,T,T,T>
в качестве имени типа - вы на самом деле получите Tuple<T,T>
.
Если заглянуть глубже в код, то он получит не зависящее от языка имя типа (например, обрабатывает '[', но ничего для '<'), так что на самом деле команда MVC должна не просто передаватьИмя типа C # прямо из нашего источника. </p>
Команда MVC должна изменить способ генерации базового типа - они могут использовать конструктор public CodeTypeReference(string typeName, params CodeTypeReference[] typeArguments)
для новогоссылку (вместо того, чтобы просто полагаться на .Add(span.BaseClass)
, создающую его), и анализировать общие параметры сами, поскольку они знают, что имя типа будет в стиле C # / VB, а не в нейтральном для языка стиле .Net с квадратными скобками и т. д.имя.