代码之家  ›  专栏  ›  技术社区  ›  bastijn

尝试成为泛型/“无类型”| ASP MVC时的强制转换问题

  •  4
  • bastijn  · 技术社区  · 15 年前

    问题

    有没有一种方法可以在C#(在helper类或其他类中)中只定义一次方法,而不知道返回哪种类型?

    长篇大论 我得到以下错误:

    无法强制转换类型为的对象 System.Data.Objects.ObjectQuery 1[WerkStageNu.Vacancies]' to type 'System.Linq.IQueryable 1[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。在我的部分课程空缺(部分课程,课程空缺由我的DB实体框架生成)中,我只做:

    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 here here

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

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

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

    现在请注意,所有这些都可以编译! 问题是我得到了以下错误:

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

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

    哦,废话,别管这部分,我忘了作为一个可计算的,仍然在使用AsQueryable。

    1 回复  |  直到 15 年前
        1
  •  5
  •   Jacob    15 年前

    在我看来,这是一个协方差与逆变的问题。基本上 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,那么如果类型参数可以由编译器隐式确定,那么您甚至不必指定它。