Почему модель моего представления не может быть привязана к моей общей ViewModel, которая реализует интерфейс? (ASP.NET MVC 3)

#c# #asp.net-mvc #asp.net-mvc-3 #interface #viewmodel

#c# #asp.net-mvc #asp.net-mvc-3 #интерфейс #viewmodel

Вопрос:

Я пытаюсь передать моему представлению экземпляр следующей ViewModel:

 public class CompanyListViewModel<T> where T : ICompany
{
    public IEnumerable<T> CompanyList;
    public IEnumerable<string> StateList;

    public CompanyListViewModel(IEnumerable<T> list)
    {
        CompanyList = list;
    }
}
  

Где представление принимает что-то вроде этого:

 @model Project.ViewModels.CompanyViewModels.CompanyListViewModel<ICompany>
  

И мой код контроллера передает что-то подобное представлению:

 CompanyListViewModel<ICompanyInListAsUser> model = new CompanyListViewModel<ICompanyInListAsUser>(_companyService.FilterByCompanyState(state));
  

Где ICompanyInListAsUser интерфейс реализует ICompany интерфейс. _companyService.FilterByCompanyState(state)) Класс возвращает IEnumerable несколько Company объектов, которые, в свою очередь, реализуют ICompanyInListAsUser интерфейс.

По какой-то причине я получаю следующую ошибку при доступе к моему представлению:

The model item passed into the dictionary is of type 'Project.ViewModels.CompanyViewModels.CompanyListViewModel`1[Project.ViewModels.CompanyViewModels.ICompanyInListAsUser]', but this dictionary requires a model item of type 'Project.ViewModels.CompanyViewModels.CompanyListViewModel`1[Project.ViewModels.CompanyViewModels.ICompany]'.

Почему я получаю эту ошибку, если ICompanyInListAsUser интерфейс фактически реализует ICompany ?

Я был бы очень признателен за любую помощь.

Спасибо.

Редактировать

Я также хотел указать, чего я пытаюсь достичь здесь. Допустим, у меня есть несколько уровней доступа в моем приложении (например. Пользователь и администратор). Что, если у меня в Company объекте есть свойство, доступное только администратору? Что ж, в таком случае моя ICompanyInListAsUser модель включала бы все свойства, которые я хотел, в виде столбцов в списке, кроме свойства, доступного только администратору.

Итак, мой план здесь состоял в том, чтобы передать как ViewModel интерфейс IEnumerable базовой компании и из контроллера (или уровня обслуживания) выборочно заполнить IEnumerable экземпляром одного из этих интерфейсов «фильтра», таких как ICompanyInListAsUser .

Надеюсь, это имеет смысл, пожалуйста, дайте мне знать, если мне нужно уточнить.

Комментарии:

1. Вы не предоставляете достаточно информации. Что такое ICompanyInListAsUser?

2. Я думаю, что использование интерфейсов в моделях представления — это очень необычный шаблон. @gazarsgo, вероятно, прав, что вы должны использовать абстрактный базовый класс.

3. Чад, ICompanyInListAsUser — это просто интерфейс, содержащий свойства, которые я хочу отфильтровать из моего доменного объекта. Райан, не мог бы ты, пожалуйста, привести краткий пример того, где именно я бы использовал абстрактный базовый класс? Вы хотите сказать, создать абстрактный базовый класс, из которого происходят все мои интерфейсы «filter» и базовый объект Company? Отсюда сделайте мою ViewModel IEnumerable списком этого абстрактного базового класса? Спасибо!

Ответ №1:

То, чего вы пытаетесь достичь, должно быть возможно с помощью интерфейса для класса ViewModel и объявления универсального типа как ковариантного. Вот так:

 interface ICompanyListViewModel<out T> where T : ICompany
{
}
  

Таким образом, вы также могли бы обойтись абстрактным классом вместо интерфейса для Company.

Ответ №2:

Подумайте о том, что интерфейсы не могут предоставлять реализации, когда вы думаете об этой ситуации, и должно стать очевидным, что вам нужно закрыть свой универсальный тип конкретным интерфейсом, с которым вы хотите, чтобы универсальный класс работал.

Если это не очевидно, что ж, рассмотрим далее, что с точки зрения чистой ООП интерфейсы не могут определять реализации, это могут только классы, и что C # не позволяет вам указывать перекрывающиеся интерфейсы.

Мне кажется, что вы пытаетесь рассматривать интерфейс как абстрактный базовый класс.

Комментарии:

1. Я понимаю, о чем вы говорите, просто мне трудно поместить это в контекст в этой ситуации.

2. так же просто, как изменить CompanyListViewModel<ICompanyInListAsUser> model = new CompanyListViewModel<ICompanyInListAsUser>(_companyService.FilterByCompanyState(state)); на CompanyListViewModel<ICompany> model = new CompanyListViewModel<ICompany>(_companyService.FilterByCompanyState(state));