【问题标题】:How do I wrap an object in a dynamic object?如何将对象包装在动态对象中?
【发布时间】:2013-06-05 01:30:16
【问题描述】:

给定一个System.Object,我如何获得一个动态对象来访问它可能拥有的任何成员。

具体来说,我想对返回 JsonResult 的 ASP.NET MVC 3 控制器操作进行单元测试。 JsonResult 具有 Data 类型的 object 属性。我用匿名类型填充这个对象:

return Json(new { Success = "Success" });

在我的测试中,我想做类似的事情

var result = controller.Foo();

Assert.That(((SomeDynamicType)result.Data).Success, Is.EqualTo("Success"));

这是怎么做到的?

更新
虽然result.Data 的类型是object,但在Watch 窗口中检查它会发现它具有以下类型:

{
    Name = "<>f__AnonymousType6`1" 
    FullName = "<>f__AnonymousType6`1[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]"
} 
System.Type {System.RuntimeType}

【问题讨论】:

  • result.Data的类型是什么?是new {...}Json 对象还是string 或...? 假设 result.Data 符合预期,它应该可以工作,这是一个可以工作的 LINQPad 示例:var x = new { X = 1 }; var y = (dynamic)x; ((object)y.X).Dump();
  • @pst,result.Data 被键入为object,但它由传递给return Json(...) 调用的new {Success = "Success"} 填充。
  • 可以看到JsonResult是如何创建的吗?我看到一个 Json 包装了 new {}...(使用的完整 Json 类型是什么?)尝试打破异常并在 Data 中查看对象的数据/类型信息。比较 new {...} 对象(也可以通过引用)和 Data 中的对象。

标签: c# unit-testing asp.net-mvc-3 dynamic expandoobject


【解决方案1】:

匿名类型是内部的,编译器以尊重这种保护的方式调用动态 api。使用 nuget 中可用的开源 ImpromptuInterface,它有一个 ImpromptuGet 类,允许您包装您的匿名类型,并将使用动态 api,就像来自匿名类型本身一样,因此您没有保护问题。

//using ImpromptuInterface.Dynamic
Assert.That(ImpromptuGet.Create(result.Data).Success, Is.EqualTo("Success"));

【讨论】:

    【解决方案2】:

    你可以使用DynamicObject的实现:

    public class MyDynamic: DynamicObject
    {
        private readonly Dictionary<string, object> dictionary = new Dictionary<string, object>();
    
        public MyDynamic(object initialData)
        {
            if (initialData == null) throw new ArgumentNullException("initialData");
            var type = initialData.GetType();
            foreach (var propertyInfo in type.GetProperties())
            {
                dictionary.Add(propertyInfo.Name, propertyInfo.GetValue(initialData, null));
            }
        }
    
        public override bool TryGetMember(GetMemberBinder binder, out object result)
        {
            dictionary.TryGetValue(binder.Name, out result);
            return true;
        }
    
        public override bool TrySetMember(SetMemberBinder binder, object value)
        {
            dictionary[binder.Name] = value;
            return true;
        }
    
    }
    

    然后:

        public void MyTest()
        {
            var json = new {Success = "Ok"};
            dynamic dynObj = new MyDynamic(json);
            Assert.AreEqual(dynObj.Success, "Ok");
        }
    

    【讨论】:

      【解决方案3】:

      既然您要检查 Json 对象,为什么不通过 JsonValueProviderFactory 运行 result.Data,然后在后备存储中搜索名为“Success”的键?

      【讨论】:

        猜你喜欢
        • 2011-09-05
        • 1970-01-01
        • 1970-01-01
        • 2017-06-12
        • 1970-01-01
        • 2011-02-13
        • 1970-01-01
        • 1970-01-01
        • 2016-08-01
        相关资源
        最近更新 更多