【问题标题】:Storing an Anonymous Object in ViewBag在 ViewBag 中存储匿名对象
【发布时间】:2012-01-23 23:20:29
【问题描述】:

这可能是一个愚蠢的问题,但我想像这样在ViewBag 中填充一个匿名对象:

ViewBag.Stuff = new { Name = "Test", Email = "user@domain.com" };

并像这样从视图中访问它:

@ViewBag.Stuff.Name

我知道 ViewBag 是动态的,并且“Stuff”是一个匿名对象……但是当我从上面的 View 行中使用调试器查看时,我可以看到所有具有正确值的属性。为什么模型绑定器在这个问题上如此困难?

有没有不创建模型类的好方法来完成此任务?我想继续使用new {}

【问题讨论】:

  • 你可以使用@ViewBag.Stuff.Name 或@ViewBag.Stuff.Email 吗?原因测试是一个值,而不是一个键/属性
  • 这是一个错字,已修复。我一直在尝试访问属性,而不是它们的值。谢谢。
  • 事实证明,这是无法做到的。看到这个:stackoverflow.com/questions/5649536/entity-framework-select-new.
  • @SoWeLie 感谢您挖掘它。我刚刚对其进行了编辑,以便更容易找到下一个人...使用此链接编辑您的答案并总结有关“内部”的内容,我会将您标记为答案。

标签: c# asp.net-mvc-3 reflection anonymous-types viewbag


【解决方案1】:

本质上问题是匿名类型是作为内部(see answer)生成的,这使得从视图中对对象属性的硬类型引用是不可能的。这篇文章提供了更详细的解释:

http://www.heartysoft.com/anonymous-types-c-sharp-4-dynamic

可以使用动态匿名包装类(@Dakill 的回答)来完成,但很快就会变得丑陋,应该让程序员质疑他/她为什么要这样做。

【讨论】:

  • 我正在寻找一个关于是否可以完成的答案,如果不能,为什么......(顺便说一句,没有否决你)
  • 那么,我再给你一个答案。但是,如果您尝试构建可维护的应用程序,我仍然坚持这个答案。
【解决方案2】:

与流行的看法相反,这是可以做到的,但涉及到一个有点丑陋的 hack,这将导致以后的维护问题。它涉及编写一个类来将您的匿名对象“包装”成一个动态对象。前段时间我把它作为一个练习,下面是包装类的代码,你可以像ViewBag.Stuff = new DynamicAnonymous(new { Name = "Test", Email = "user@domain.com" });..一样使用它。

public class DynamicAnonymous : DynamicObject
{
            object obj;

            public DynamicAnonymous(object o)
            {
                    this.obj = o;
            }

            public override IEnumerable<string> GetDynamicMemberNames()
            {
                    return obj.GetType().GetProperties().Select(n => n.Name);
            }

            public override bool TryGetMember(GetMemberBinder binder, out object result)
            {
                    var prop = obj.GetType().GetProperty(binder.Name);
                    if (prop == null)
                    {
                            result = null;
                            return false;
                    }
                    else
                    {
                            result = prop.GetValue(obj, null);
                            return true;
                    }
            }

            public override int GetHashCode()
            {
                    return obj.GetHashCode();
            }

            public override string ToString()
            {
                    return obj.ToString();
            }

            public override bool Equals(object obj2)
            {
                    return obj.Equals(obj2);
            }                
 }

【讨论】:

    【解决方案3】:

    我们可以很好地使用 Json 实现这一目标

    控制器:对象 -> json 字符串,视图:Json 字符串 -> 对象

    场景只是控制器类将C#对象序列化为json字符串 然后稍后视图接收此字符串并将其反序列化为一个对象,如下所示:

    在控制器中:

    using Newtonsoft.Json;
    ViewBag.Stuff = JsonConvert.SerializeObject(new { Name = "Test", Email = "user@domain.com" });
    

    在视图中:

    @using Newtonsoft.Json
    <p>@JsonConvert.DeserializeObject(ViewBag.Stuff).Name</p>
    

    注意:这是在 Asp.Net Core 2.2 中测试的 , 检查该链接以安装Newtonsoft.Json

    【讨论】:

      【解决方案4】:

      您可以使用 NothingsImpossible 所描述的机制来实现,但无需使用 ExpandoObject 实现您自己的包装器。这是一个例子:

      var items = _repository.GetItems()
          .Select(og => {
              dynamic eo = new System.Dynamic.ExpandoObject();
              eo.Id = item.Id;
              eo.FriendlyName = og.FriendlyName;
              eo.Selected = itemIds.Contains(item.Id);
              return eo;
          })
          .ToArray();
      ViewBag.Items = items;
      

      【讨论】:

        猜你喜欢
        • 2021-03-17
        • 2017-11-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-04-27
        • 2011-09-17
        • 2017-06-03
        相关资源
        最近更新 更多