尝试通用/'免费'时出现问题| ASP MVC

bas*_*ijn 4 c# asp.net asp.net-mvc

有没有办法在C#中定义一个方法(在辅助类或其他东西中)不知道返回哪种类型?

很长的解释 我得到以下错误:

无法转换System.Data.Objects.ObjectQuery 1[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);

    }
Run Code Online (Sandbox Code Playgroud)

现在,这个搜索仅适用于职位空缺.但是可以想象我们在整个地方都搜索了相同的例程,因此我想调用相同的方法来获取不同的类型.对于这种情况,我创建了一个接口,IFilteredEntities.在我的部分班级空缺职位(部分班级,职业空缺由我的数据库实体框架生成)我只是这样做:

public partial class Vacancies : IFilteredEntities
Run Code Online (Sandbox Code Playgroud)

当然,实现接口中没有默认实现的方法.在我的界面中我有:

    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; }
}
Run Code Online (Sandbox Code Playgroud)

为方便起见,我在这里这里上传了两个辅助类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;
    }
Run Code Online (Sandbox Code Playgroud)

为方便起见,这是我的解决方案资源管理器的一部分图片:

Solution Explorer http://www.bastijn.nl/zooi/solutionexplorer.png

简而言之:

我尝试做的不是像:

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);
Run Code Online (Sandbox Code Playgroud)

使用接口调用显示的变体,因此我只需要定义te"Filter"方法一次,而不是所有类/模型.现在注意所有这些都要编译!问题是我收到以下错误:

Unable to cast object of type 'System.Data.Objects.ObjectQuery`1[WerkStageNu.Vacancies]' to type 'System.Linq.IQueryable`1[WerkStageNu.Models.IFilteredEntities]'.
Run Code Online (Sandbox Code Playgroud)

我希望我没有忘记任何信息,但我已经盯着这段代码了一段时间.可能会忘记关系或某事,如果我这样做就问它:).

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

编辑后编辑

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

O废话,没关系这部分,我忘了AsEnumerable,仍然使用AsQueryable.

Jac*_*cob 5

在我看来,这是一个协方差与逆变问题.基本上,即使Vacancies实现了IFilteredEntities ,IQueryable<Vacancies>它也不是子类型IQueryable<IFilteredEntities>.因此,具有强制转换的行导致运行时错误.所以,而不是做演员而不是尝试:

IEnumerable<IFilteredEntities> selectedListings =
    Repository.Instance._entities.Vacancies.AsQueryable()
    .OfType<IFilteredEntities>();
Run Code Online (Sandbox Code Playgroud)

这将做的是将集合的每个元素投影到IFilteredEntities类型.

另一个选择是重写您的过滤器方法,以便他们使用泛型,如下所示:

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

然后,这将允许您传入包含从IFilteredEntities派生的任何类型的集合,并返回相同类型的集合.如果你正在使用C#3,你甚至不必指定类型参数,如果它可以由编译器隐式确定.