Кастинг анонимного типа для динамического
У меня есть функция, которая возвращает анонимный тип, который я хочу протестировать в моем 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);
}
Ответы
Ответ 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))