Вопрос по asp.net-mvc, asp.net, c# – Проблемы с кастингом при попытке быть универсальным / 'type free' | ASP MVC

4

Question

Есть ли способ определить метод только один раз в C # (в классе помощника или что-то), не зная, какой тип дается для возврата?

Long explanation Я получаю следующую ошибку:

Unable to cast object of type System.Data.Objects.ObjectQuery1[WerkStageNu.Vacancies]' to type 'System.Linq.IQueryable1[WerkStageNu.Models.IFilteredEntities]'.

У меня есть ListingsController, который выполняет поиск по моим текущим вакансиям в базе данных:

public ActionResult Search(int? page, string branchid, string hoursago, string jobtypeid, string educationlevelid, string careerlevelid)
    {
        string searchResult = string.Empty;
        const int pageSize = 10;

        IQueryable<IFilteredEntities> selectedListings = (IQueryable<IFilteredEntities>)Repository.Instance._entities.Vacancies.AsQueryable();

        Dictionary<string, string> filterParams = new Dictionary<string, string>() {
            {"branchid", branchid}, {"hoursago", hoursago}, {"jobtypeid", jobtypeid}, {"educationlevelid", educationlevelid}, {"careerlevelid", careerlevelid}};

        selectedListings = FilterByIDHelper.Filter(selectedListings, filterParams);

        var paginatedDinners = new PaginatedList<Vacancies>(((IQueryable<Vacancies>)selectedListings).ToList(), page ?? 0, pageSize);
        return View("Index", paginatedDinners);

    }

Теперь этот поиск только для вакансий. Но можно предположить, что у нас везде и везде один и тот же поиск, поэтому я хочу вызвать один и тот же метод для получения разных типов. Для этого случая я сделал интерфейс IFilteredEntities. В моем частичном классе Vacancies (частичный класс, класс Vacancies создается моей структурой сущностей БД) я просто делаю:

public partial class Vacancies : IFilteredEntities

И, конечно, реализовать методы в интерфейсе, которые не реализованы по умолчанию. В моем интерфейсе у меня есть:

    interface IFilteredEntities
{
    string EducationLevelID { get; set; }
    string BrancheID { get; set; }
    string CareerLevelID { get; set; }
    string JobTypeID { get; set; }

    Branches Branches { get; set; }
    DateTime? DateOfCreation { get; set; }
    CareerLevels CareerLevels { get; set; }
    JobTypes JobTypes { get; set; }
    EducationLevels EducationLevels { get; set; }
}

Для удобства я загрузил два вспомогательных класса PaginatedList и FilterCriteriaHelperВот а такжеВот.

Теперь метод, который будет выполнять фактическую фильтрацию, находится внутри другого вспомогательного класса: FilterByIDHelper.cs.

 public static IQueryable<IFilteredEntities> Filter(IQueryable<IFilteredEntities> collection, Dictionary<string, string> filterParams)
    {
        if (filterParams.ContainsKey("branchid")) collection = FilterByBranchId(collection, filterParams["branchid"]);
        if (filterParams.ContainsKey("hoursago")) collection = FilterByHoursAgo(collection, filterParams["hoursago"]);
        if (filterParams.ContainsKey("jobtypeid")) collection = FilterByJobTypeId(collection, filterParams["jobtypeid"]);
        if (filterParams.ContainsKey("educationlevelid")) collection = FilterByEducationLevelId(collection, filterParams["educationlevelid"]);
        if (filterParams.ContainsKey("careerlevelid")) collection = FilterByCareerLevelId(collection, filterParams["careerlevelid"]);

        return collection;
    }

public static IQueryable<IFilteredEntities> Filter(IQueryable<IFilteredEntities> collection, Dictionary<string, string> filterParams)
    {
        if (filterParams.ContainsKey("branchid")) collection = FilterByBranchId(collection, filterParams["branchid"]);
        if (filterParams.ContainsKey("hoursago")) collection = FilterByHoursAgo(collection, filterParams["hoursago"]);
        if (filterParams.ContainsKey("jobtypeid")) collection = FilterByJobTypeId(collection, filterParams["jobtypeid"]);
        if (filterParams.ContainsKey("educationlevelid")) collection = FilterByEducationLevelId(collection, filterParams["educationlevelid"]);
        if (filterParams.ContainsKey("careerlevelid")) collection = FilterByCareerLevelId(collection, filterParams["careerlevelid"]);

        return collection;
    }

Для удобства вот часть моего обозревателя решений:

Обозреватель решений http://www.bastijn.nl/zooi/solutionexplorer.png

In short:

То, что я пытаюсь сделать, это вместо звонить, как:

selectedListings = Repository.Instance._entities.Vacancies.AsQueryable();
Dictionary<string, string> filterParams = new Dictionary<string, string>() {
        {"branchid", branchid}, {"hoursago", hoursago}, {"jobtypeid", jobtypeid}, {"educationlevelid", educationlevelid}, {"careerlevelid", careerlevelid}};

    selectedListings = FilterByIDHelper.Filter(selectedListings, filterParams);

    var paginatedDinners = new PaginatedList<Vacancies>(selectedListings.ToList(), page ?? 0, pageSize);
    return View("Index", paginatedDinners);

Вызвать вариант, показанный выше, используя интерфейс, поэтому мне нужно только определить te & quot; Filter & quot; метод один раз вместо всех классов / моделей.Now Notice that all of this DOES compile! Проблема в том, что я получаю следующую ошибку:

Unable to cast object of type 'System.Data.Objects.ObjectQuery`1[WerkStageNu.Vacancies]' to type 'System.Linq.IQueryable`1[WerkStageNu.Models.IFilteredEntities]'.

Я надеюсь, что не забыл никакой информации, но уже некоторое время смотрю на этот код. Можете забыть отношения или что-то, просто спросите об этом, если я сделал :).

-----------------------------------------------------

EDIT AFTER COMMENTS

-----------------------------------------------------

О дерьмо, не обращайте внимания на эту часть, я забыл, как AsEnumerable, все еще использовал AsQueryable.

Большое спасибо, бонусные очки будут даны для человека, который приложит столько же усилий в своем ответе :). bastijn
Может быть, вы также должны пометить это как c #. Это не только для ASP.NET MVC. Mathias F
Ты работаешь на монстра? User
Бонусные баллы за усилия, которые вы вложили в вопрос! Marc Gravell♦
А что? Я думаю, нет :). bastijn

Ваш Ответ

1   ответ
5

это проблема ковариации против контравариантности. В основном,IQueryable<Vacancies> не является подтипомIQueryable<IFilteredEntities>, хотя Вакансии реализует IFilteredEntities. Таким образом, строка с приведением вызывает ошибку во время выполнения. Так что вместо того, чтобы делать бросок, попробуйте это:

IEnumerable<IFilteredEntities> selectedListings =
    Repository.Instance._entities.Vacancies.AsQueryable()
    .OfType<IFilteredEntities>();

Это будет проецировать каждый элемент коллекции на тип IFilteredEntities.

Другой вариант - переписать ваши методы фильтра, чтобы они использовали обобщенные значения, например:

public static IEnumerable<T> Filter<T>(
    IEnumerable<T> collection, IDictionary<string, string> filterParams)
    where T : IFilteredEntities
{
    ...
}

Это позволит вам затем передать коллекцию, содержащую любой тип, производный от IFilteredEntities, и получить коллекцию того же типа. И если вы используете C # 3, вам даже не нужно указывать параметр типа, если он может быть неявно определен компилятором.

Error: User Rate Limit Exceeded bastijn
Error: User Rate Limit Exceeded bastijn

Похожие вопросы