在ViewBag中存储匿名对象

时间:2012-01-23 23:20:30

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

这可能是一个愚蠢的问题,但我试图在ViewBag中填写一个匿名对象:

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

并从视图中访问它:

   

@ ViewBag.Stuff.Name

我理解ViewBag是动态的,“Stuff”是一个匿名对象...但是当我从上面的View行查看调试器时,我可以看到具有正确值的所有属性。为什么模型装订器有这么难?

有没有一种很好的方法可以在不创建模型类的情况下实现这一目标?我想继续使用new {}

4 个答案:

答案 0 :(得分:8)

基本上问题是匿名类型是作为内部(see answer)生成的,从View中无法对对象的属性进行硬类型引用。本文提供了更详细的解释:

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

使用动态匿名包装类(@Dakill的答案)可以实现,但是快速变得难看并且应该让程序员质疑为什么他/她会这样做。

答案 1 :(得分:5)

与流行的看法相反,这可以做到,但涉及到一些有点丑陋的黑客攻击会导致维护问题。它涉及编写一个类来将您的匿名对象“包装”成动态对象。我之前做过一个练习,下面是包装类的代码,你会像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);
            }                
 }

答案 2 :(得分:1)

我们可以使用Json来实现这一目标

  

Controller:object-> json string,View:Json string-> object

     

scenerio只是控制器类,将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

答案 3 :(得分:0)

您可以使用NothingsImpossible descibed机制来完成它,但是使用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;