我有一个函数返回一个匿名类型,我想在我的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);
}
答案 0 :(得分:36)
匿名对象是internal
,这意味着他们的成员在声明它们的程序集之外非常受限制。 dynamic
尊重可访问性,因此假装无法看到这些成员。如果呼叫站点在同一个程序集中,我希望它可以工作。
您的反射代码尊重成员辅助功能,但会绕过该类型的辅助功能 - 因此它可以正常工作。
简而言之:不。
答案 1 :(得分:25)
这个博客有一个有效的答案:http://blog.jorgef.net/2011/06/converting-any-object-to-dynamic.html - 谢谢@ Jorge-Fioranelli。
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;
}
}
答案 2 :(得分:7)
匿名类型是.NET中的常规静态类型,只是你没有给它起一个名字(但编译器也是如此)。这就是为什么把它投射到dynamic
是行不通的。但是,如果您可以控制Foo()
,则可以构造并返回dynamic
对象而不是匿名对象,然后您的代码将起作用。这应该可以解决问题:
dynamic JsonResult Foo() {
dynamic data = new ExpandoObject();
data.details = "something";
data.mode = "More";
return Json(data);
}
答案 3 :(得分:7)
正如@TrueWill和@Marc Gravell所建议的那样,他也提到this blog post
由于这是用于单元测试,因此可以使用InternalsVisibleTo。请参阅匿名类型是内部的,C#4.0动态小心!感谢@MarcGravell指出匿名对象是内部的!
底线:如果要将匿名对象从一个程序集共享到另一个程序集,请设置[assembly: InternalsVisibleTo("foo")]
映射。在OP情况下,将在MVC控制器项目中设置此项,参考测试项目。在我的具体情况下,反过来(因为我将一个匿名对象从我的测试项目传递到“生产代码”项目)。
“其他项目”能够使用它的最简单方法是将其强制转换为dynamic
,然后只使用正常的属性。它确实有效,没有任何问题。
所以,底线:我觉得Marc Gravell的回答有些不正确;这显然可以做到 ( iff 有问题的项目可由您修改,因此您可以相应地设置InternalsVisibleTo映射,这不会因其他原因造成问题。)
答案 4 :(得分:1)
您可以使用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))