Подтвердить что ты не робот

Динамически типизированный ViewPage

Возможно ли это? Вот что я пытаюсь:

    public ActionResult Index()
    {
        dynamic p = new { Name = "Test", Phone = "111-2222" };
        return View(p);
    }

И тогда мое представление наследует от System.Web.Mvc.ViewPage<dynamic> и пытается распечатать Model.Name.

Я получаю сообщение об ошибке: '< > f__AnonymousType1.Name' недоступен из-за уровня защиты

Итак, в основном, это то, что я пытаюсь сделать, просто невозможно? Почему или почему нет?

Обновление: здесь мой взгляд

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<dynamic>" %>

<asp:Content ...>
    <%=Model.Name%>
    <%=Model.Phone%>
</asp:Content>

Конструктор View встроен в фреймворк.

4b9b3361

Ответ 1

Неизвестные типы не могут быть возвращены методом; они действительны только в рамках метода, в котором они определены.

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

Обновление

Я думаю, что раньше был неправ. Это должно сработать. Возможно, проблема находится в представлении. Можете ли вы разместить больше кода? Особенно View и его конструктор.

Обновить второе:

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

Но я также ошибался в своем убеждении, что то, что вы пытаетесь сделать, будет работать. К сожалению, для вас это не так. Проблема в том, что вы используете ViewPage<TModel>, который использует ViewDataDictionary<TModel> внутренне. Поскольку они требуют сильных типов, вы не сможете использовать с ними динамические объекты. Внутренняя структура не использует внутреннюю динамику и указывает динамику по мере того, как тип терпит неудачу.

Для чего нужен класс DynamicViewPage и соответствующий класс DynamicViewDataDictionary, которые принимают object и сохраняют его внутренне как динамическое. Затем вы можете использовать анонимный тип и передать его в свои представления.

Тем не менее, вы ничего не выиграете. Вы могли бы указать свои Представления, как вы это делали (т.е. <%=Model.Name%>), но вы не получили бы сильную типизацию. Не было бы никакой интеллигенции и не было бы никакой безопасности типа. Вы бы так же хорошо использовали нетипизированный ViewDataDictionary, как предлагает @Dennis Palmer.

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

Ответ 2

Какую пользу вы надеялись получить от использования динамического типа здесь?

Использование словаря ViewData - очень простой способ добавить к вашему представлению любые объекты/элементы.

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

Изменить: Я только немного узнал о динамике, и я думаю, возможно, вам нужно создать свой собственный класс динамических объектов, который наследуется от DynamicObject. Вы захотите иметь частный словарь в этом классе, а затем переопределить TrySetMember и TryGetMember.

Редактировать в стороне: Я думаю, что одно преимущество сильно типизированного ViewModel заключается в том, что вы можете принять его как параметр в методах POST-действия. Структура MVC будет обрабатывать привязку модели, и в методе действий у вас просто есть экземпляр класса ViewModel. Я не думаю, что у вас будет такое преимущество при динамике, даже если они будут работать.

Изменить результат: Ну, я попытался использовать класс, полученный из DynamicObject, но VS2010 падает, когда он пытается отобразить представление. Я не получаю никаких исключений, просто жесткий сбой и перезагрузка Visual Studio. Здесь код, который я придумал, вызывает сбой.

Пользовательский динамический класс:

public class DynViewModel : DynamicObject
{
    private Dictionary<string, object> ViewDataBag;
    public DynViewModel()
    {
        this.ViewDataBag = new Dictionary<string, object>();
    }
    public override bool TrySetMember(SetMemberBinder binder, object value)
    {
        this.ViewDataBag[binder.Name] = value;
        return true;
    }
    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        result = this.ViewDataBag[binder.Name];
        return true;
    }
}

В контроллере:

public ActionResult DynamicView()
{
    dynamic p = new DynamicViewModel.Models.DynViewModel();
    p.Name = "Test";
    p.Phone = "111-2222";

    return View(p);
}

Мой взгляд в основном совпадает с тем, что указано в вопросе:

<p>Name: <%=Model.Name %></p>
<p>Phone: <%=Model.Phone %></p>

Мое заключение: Это может сработать, но в бета-версии 1 VS2010 я не могу понять, почему мой код заставляет Visual Studio сбой. Я попробую еще раз в VS2010 Beta 2, когда он будет выпущен, потому что это интересное упражнение в изучении динамики. Однако, даже если это будет работать, я по-прежнему не вижу никакого преимущества перед использованием словаря ViewData.

Фил Хаак на помощь! Вот сообщение в блоге Phil Haack, которое может помочь вам. Похоже, это то, что вы искали. Fun With Method Missing и С# 4

Ответ 3

Фактическая ошибка здесь (<>f__AnonymousType1.Name' is inaccessible due to its protection level) является результатом использования анонимных типов. Анонимные типы неявно internal (по крайней мере, на С#), поэтому их можно получить только из обычной сборки. Поскольку ваше представление скомпилировано в отдельную сборку во время выполнения, оно не может получить доступ к анонимному типу internal.

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

Ответ 4

В .NET 4.0 Анонимные типы могут быть легко преобразованы в ExpandoObjects, и, следовательно, все проблемы устраняются с накладными расходами самого преобразования. Проверьте здесь