“object”不包含“X”的定义。

42

我之前遇到过这个问题,但没有解决。我有一个列表(在MVC3控制器中生成):

ViewBag.Languages = db.Languages
    .Select(x => new { x.Name, x.EnglishName, x.Id })
    .ToList();

然后在我的页面(使用 Razor)中,我尝试对其进行迭代:

foreach (var o in ViewBag.Languages)
{
    string img = "Lang/" + o.EnglishName + ".png";
    @* work *@
}

但是对于 o.EnglishName 的引用会出现以下错误:

'object' 不包含名为 'EnglishName' 的定义

但有趣的是,如果我在调试时输入以下内容到“直接窗口”中:

o
{ Name = བོད་སྐད་, EnglishName = Tibetan, Id = 31 }
    EnglishName: "Tibetan"
    Id: 31
    Name: "བོད་སྐད་"

很明显该字段已经存在。那么我的问题是什么呢?


真正的答案在这里:https://dev59.com/f2435IYBdhLWcg3w9E9Y - Alex from Jitbit
4个回答

79

您在此处使用了一个匿名对象:

ViewBag.Languages = db.Languages
    .Select(x => new { x.Name, x.EnglishName, x.Id })
    .ToList();

匿名对象由编译器作为internal发出。Razor视图会被ASP.NET运行时自动编译成单独的程序集。这意味着您无法访问在控制器中生成的任何匿名对象。

因此,为了解决问题,您可以定义一个视图模型:

public class LanguageViewModel
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string EnglishName { get; set; }
}

然后在您的控制器中使用此视图模型:

ViewBag.Languages = db.Languages
    .Select(x => new LanguageViewModel
    { 
        Name = x.Name, 
        EnglishName = x.EnglishName, 
        Id = x.Id 
     })
    .ToList();

现在你有了一个视图模型,接下来改进你的代码的自然步骤是摆脱这个我已经厌烦看到的ViewBag,并且简单地使用视图模型和强类型:

public ActionResult Foo()
{
    var model = db
        .Languages
        .Select(x => new LanguageViewModel
        { 
            Name = x.Name, 
            EnglishName = x.EnglishName, 
            Id = x.Id 
        })
        .ToList();
    return View(model);
}

然后当然需要有一个强类型视图:

@model IEnumerable<LanguageViewModel>
@Html.DisplayForModel()

接着定义相应的显示模板,ASP.NET MVC引擎会自动为视图模型中的每个元素呈现该模板,因此您甚至不需要在视图中编写任何foreach语句(~/Views/Shared/DisplayTemplates/LanguageViewModel.cshtml):

@model LanguageViewModel
... generate the image or whatever you was attempting to do in the first place

1
哇,太棒了回复(+1)。非常感谢 - 是的,我正在删除所有对ViewBag的引用,转而使用视图模型... - ekkis
1
非常好,但有时我们可能需要使用ViewBags。我们只能将一个模型传递给一个视图。然而,我们可能想要发送一些其他的小数据集合,不是吗?在这种情况下,使用ViewBags更容易。当然,您也可以使用PartialViews发送它。我不知道是否有其他建议。 - oneNiceFriend
@Darin - 我不知道匿名对象,尤其是ExpandoObject属性,在另一个程序集中是无法访问的。它们不被视为“对象”的“属性”。当你说它们是internal时,这很有道理。这帮助我在VSTO场景中解决了我的问题。 - Leo Gurdian
那个新的 { } 真的很不错。谢谢! - Mihai

4
这让我很苦恼,直到我检查了我的代码并发现这个问题:
class AdsViewModel
{
    public int Id { get; set; }
    public  string City { get; set; }
    public string CompanyName { get; set; }
    public string ContactName { get; set; }
    public string UserEmail { get; set; }
    public string ContactPhone { get; set; }
    public string ShortTitle { get; set; }
    public string AdUrl { get; set; }
}

将其改为:
public class AdsViewModel 

问题已解决。


1
请使用ViewData而不是ViewBag。
ViewData["Lang"] = db.Languages
.Select(x => new { x.Name, x.EnglishName, x.Id })
.ToList();

那么

foreach (var o in (dynamic) ViewData["Lang"])
{
string img = "Lang/" + o.EnglishName + ".png";
@* work *@
}

0

如果你的类名与文件名不匹配,也可能会发生这种情况(我知道这很愚蠢,但这可能会帮助你)


似乎是特定的嵌套类可能会引起问题。 - ChrisO

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接