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

Кастинг анонимного типа для динамического

У меня есть функция, которая возвращает анонимный тип, который я хочу протестировать в моем MVC-контроллере.

public JsonResult Foo()
{
    var data = new
                  {
                      details = "something",
                      more = "More"
                  };
    return Json(data);
}

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

[Test]
public void TestOne()
{
    var data = _controller.Foo().Data;
    var details = data.GetType().GetProperty("details").GetValue(data, null);
    var more = data.GetType().GetProperty("more").GetValue(data, null);

    Assert.AreEquals("something", details);
    Assert.AreEquals("More", more);
}

Есть ли простой способ, аналогичный этому, проверить анонимные свойства?

[Test]
public void TestTwo()
{
    var data = (dynamic) _controller.Foo().Data;
    var details = data.details; // RunTimeBinderException object does not contain definition for details
    var more = data.more;

    Assert.AreEquals("something", details);
    Assert.AreEquals("More", more);
}
4b9b3361

Ответ 1

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

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

Короче: нет.

Ответ 2

В этом блоге был рабочий ответ: http://blog.jorgef.net/2011/06/converting-any-object-to-dynamic.html - Спасибо @Хорхе-Фиоранелли.

public static class DynamicExtensions {
    public static dynamic ToDynamic(this object value) {
        IDictionary<string, object> expando = new ExpandoObject();

        foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(value.GetType()))
            expando.Add(property.Name, property.GetValue(value));

        return expando as ExpandoObject;
    }
}

Ответ 3

Анонимный тип - это обычный статический тип в .NET, он просто не дает ему имени (однако, компилятор). То, что приведение его к dynamic не будет работать. Однако, если у вас есть контроль над Foo(), вы можете создать и вернуть объект dynamic вместо анонимного, а затем ваш код будет работать. Это должно сделать трюк:

dynamic JsonResult Foo() {
    dynamic data = new ExpandoObject();
    data.details = "something";
    data.mode = "More";
    return Json(data);
}

Ответ 4

Как было предложено @TrueWill и @Marc Gravell, который также ссылался на этот пост в блоге

Так как это для модульного тестирования, вы можете использовать InternalsVisibleTo. См. Анонимные типы являются внутренними, С# 4.0 Динамический Осторожно! Спасибо @MarcGravell за указание, что анонимные объекты являются внутренними!

Нижняя строка: настройте сопоставление [assembly: InternalsVisibleTo("foo")], если вы хотите поделиться анонимным объектом с одной сборки на другую. В случае OP это будет вопрос об установке этого в проекте контроллера MVC, ссылаясь на тестовый проект. В моем конкретном случае, наоборот (поскольку я передаю анонимный объект из моего тестового проекта в проект "производственный код" ).

Самый простой способ использования этого "другого проекта" - это, безусловно, бросить его на dynamic, а затем просто использовать свойства, как обычно. Это действительно работает, никаких проблем.

Итак, нижняя строка: я чувствую, что ответ Марка Гравелла немного неверен; это можно сделать однозначно (если эти проекты могут быть изменены вами, поэтому вы можете соответствующим образом настроить отображение InternalsVisibleTo, и это не создает проблемы по какой-либо другой причине).

Ответ 5

Вы можете использовать библиотеки NewtonSoft или Asp.net MVC:

var data = Json.Decode(Json.Encode(_controller.Foo().Data));

var data=JsonConvert.DeserializeObject<Dictionary<string,object>>(JsonConvert.SerializeObject((_controller.Foo().Data))