web-dev-qa-db-de.com

'Objekt' enthält keine Definition für 'X'

Ich hatte dieses Problem schon einmal und konnte es nicht lösen. Ich habe eine Liste (in einer MVC3-Steuerung generiert):

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

und auf meiner Seite (Razor) versuche ich es zu durchlaufen:

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

der Verweis auf o.EnglishName schlägt jedoch fehl mit dem Fehler:

'object' enthält keine Definition für 'EnglishName'

das Merkwürdige ist jedoch, dass ich, wenn ich in das Direktfenster eingebe (beim Debuggen):

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

so offensichtlich ist das Feld da. Was ist mein Problem hier?

34
ekkis

Sie verwenden hier ein anonymes Objekt:

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

Anonyme Objekte werden vom Compiler als internal ausgegeben. Die Razor-Ansichten werden von der ASP.NET-Laufzeitumgebung automatisch in eine separate Assembly kompiliert. Das bedeutet, dass Sie nicht auf anonyme Objekte zugreifen können, die in Ihren Controllern generiert wurden.

Um Ihr Problem zu beheben, können Sie ein Ansichtsmodell definieren:

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

und dann in Ihrem Controller dieses Ansichtsmodell verwenden:

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

Und jetzt, da Sie über ein Ansichtsmodell verfügen, besteht die nächste Verbesserung Ihres Codes natürlich darin, diesen Mist von ViewBag zu beseitigen, den ich satt sehen kann, und einfach Ansichtsmodelle und starkes Tippen verwenden:

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

und dann natürlich eine stark typisierte Sicht:

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

definieren Sie dann die entsprechende Anzeigevorlage, die automatisch von der ASP.NET MVC-Engine für jedes Element des Ansichtsmodells gerendert wird, sodass Sie nicht einmal einen einzelnen foreach in Ihren Ansichten schreiben müssen (~/Views/Shared/DisplayTemplates/LanguageViewModel.cshtml):

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

Dies war für mich ein Ersatz, bis ich meinen Code überprüft und Folgendes gefunden hatte:

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; }
}

Ändern Sie es in:

public class AdsViewModel 

Behoben.

4

Es kann auch vorkommen, wenn der Name Ihrer Klasse nicht mit dem Namen der Datei übereinstimmt (ich weiß, dass es dumm ist, aber es kann Ihnen helfen)

0

Bitte verwenden Sie ViewData anstelle von ViewBag.

ViewData["Lang"] = db.Languages
.Select(x => new { x.Name, x.EnglishName, x.Id })
.ToList();

Dann

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