【问题标题】:IList<variableType>; Solve without GenericsIList<变量类型>;不使用泛型求解
【发布时间】:2009-08-03 00:56:36
【问题描述】:

我发现了许多类似的问题,但没有找到我想要的答案。我的部分问题是由于无法在属性中使用泛型。

我可能试图让事情变得过于复杂,所以如果你能想到更简单的方法,我会全力以赴。

我的具体问题与 ASP.NET MVC 有关,在 Action 方法上使用属性(过滤器)。我正在尝试创建一个过滤器,对传递给 ViewData.Model 的结果进行分页,如下所示:

[PagedList(PageSize = 2, ListType = typeof(Invoice))]
public ViewResult List()
{
    var invoices = invoicesRepository.Invoices; // Returns an IQueryable<Invoice>
    return View(Invoices);
}

我的过滤器的 OnActionExecuted 覆盖如下:

public override void OnActionExecuted(ActionExecutedContext filterContext)
{
    ViewResult result = (ViewResult)filterContext.Result;
    var list = (IQueryable<?>)result.ViewData.Model; // Here I want to use the ListType in place of the ?

    // Perform pagination
    result.ViewData.Model = list.Skip((Page - 1) * PageSize).Take(PageSize.ToList();
}

我意识到我可以替换我的

var list = (IQueryable<?>)result.ViewData.Model;

var list = (IQueryable)result.ViewData.Model;
IQueryable<Object> oList = list.Cast<Object>();

但是我的视图是强类型的,期望一个

IQueryable<Invoice>

不是

IQueryable<Object>

【问题讨论】:

    标签: c# asp.net-mvc generics attributes


    【解决方案1】:

    您能否在过滤器中创建一个通用方法来执行您需要执行的操作,然后在OnActionExecuted 中使用反射通过ListType 调用该通用方法?


    编辑:例如,您将使用此签名创建一个新方法:

    private void GenericOnActionExecuted<T>( ActionExecutedContext filterContext )
    

    此方法的代码与您发布的代码相同。然后你会像这样重写OnActionExecuted

    public void OnActionExecuted( ActionExecutedContext filterContext )
    {
        MethodInfo genericMethod =
            GetType().GetMethod( "GenericOnActionExecuted",
                BindingFlags.Instance | BindingFlags.NonPublic );
    
        MethodInfo constructedMethod = genericMethod.MakeGenericMethod( ListType );
    
        constructedMethod.Invoke( this, new object[] { filterContext } );
    }
    

    【讨论】:

    • 我仍然需要以某种方式传递类型,这就是我坚持的部分:Type type = typeof(Invoice); // 我可以将其作为属性传递 myNewMethod(); // 但我不能这样做?
    【解决方案2】:

    我自己从未使用过 ASP.NET MVC,但根据您的解释,我会说您有两种选择。这两种解决方案都要求您将通用版本的 OnActionExecuted 添加到您的属性中。

    protected void DoActionExecuted<T>(ActionExecutedContext filterContext)
    {
        var result = (ViewResult) filterContext.Result;
        var list = (IQueryable<T>) result.ViewData.Model;
        result.ViewData.Model = list.Skip((Page - 1)*PageSize)
                                    .Take(PageSize)
                                    .ToList();
    }
    

    您可以使用反射来调用具有动态类型参数的方法:

    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        GetType().GetMethod("DoActionExecuted",
                            BindingFlags.NonPublic | BindingFlags.Instance)
                 .MakeGenericMethod(ListType)
                 .Invoke(this, new[] {filterContext});
    }
    

    或者您可以创建一个在编译时知道泛型类型的私有属性子类:

    [PagedInvoiceList(PageSize = 2, ListType = typeof (Invoice))]
    public ViewResult List() { ... }
    
    private class PagedInvoiceListAttribute : PagedListAttribute
    {
        public override void OnActionExecuted(ActionExecutedContext filterContext)
        {
            DoActionExecuted<Invoice>(filterContext);
        }
    }
    

    【讨论】:

    • 非常感谢内森!这与 Tinister 提供的答案相同,但似乎我只能奖励一个人“接受的答案”:(
    【解决方案3】:

    据我所知,这在您试图实现的过程中从困难到不可能。

    如果我正确理解了你的问题,那么你想做这样的事情:

      var someGenericResult = (IQueryable<typeof(SomeType)>)result.ViewData.Model;
    

    您也许可以尝试使用信息 here,但我不知道它是否会在您的特定情况下对您有所帮助,因为您正在使用接口传递信息——正如你应该做的那样——并且有还是类型转换的问题。

    【讨论】:

    • 谢谢和梅多斯!按照您的链接后,它似乎以与其他两个相同的方式回答我的问题。不幸的是,我似乎只能授予一个“已接受的答案”:(
    • 不用担心。其他 cmets 更详细。很高兴你成功了!
    猜你喜欢
    • 2013-01-11
    • 1970-01-01
    • 1970-01-01
    • 2020-04-21
    • 1970-01-01
    • 2020-06-20
    • 1970-01-01
    • 1970-01-01
    • 2023-04-10
    相关资源
    最近更新 更多