"объект" не содержит определения для "X"
У меня была эта проблема однажды, и я не решил ее. У меня есть список (сгенерированный в контроллере 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'
хотя любопытно, что если я наберу в Immediate Window (во время отладки):
o { Name = བོད་སྐད་, EnglishName = Tibetan, Id = 31 } EnglishName: "Tibetan" Id: 31 Name: "བོད་སྐད་"
так очевидно, что поле здесь. В чем моя проблема здесь?
4 ответа
Вы используете анонимный объект здесь:
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
Это сводило меня с ума, пока я не проверил свой код и не нашел это:
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
Починил это.
Пожалуйста, используйте 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 *@
}
Это также может произойти, если имя вашего класса не совпадает с именем файла (я знаю, что это глупо, но это может вам помочь)