2009-08-03 4 views
1

J'ai trouvé beaucoup de questions similaires mais rien avec tout à fait la réponse que je suis après. Une partie de mon problème est due à l'incapacité d'utiliser des génériques dans les attributs. Je suis probablement en train d'essayer de compliquer les choses, donc si vous pouvez trouver une façon plus simple de faire cela, je suis tout ouïe.IList <variableType>; Résoudre sans génériques

Mon problème spécifique concerne ASP.NET MVC, en utilisant des attributs (filtres) sur une méthode d'action. Je suis en train de créer un filtre qui paginera les résultats transmis à la ViewData.Model comme ceci:

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

OnActionExecuted override Mon filtre ressemble alors:

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

Je me rends compte que je pouvais remplacer mon

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

Avec

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

Mais mon avis est fortement typée d'attendre une

IQueryable<Invoice> 

pas

IQueryable<Object> 

Répondre

4

Pouvez-vous créer potentiellement une méthode générique dans votre filtre qui fait ce que vous devez faire, puis à l'intérieur OnActionExecuted utiliser la réflexion pour appeler cette méthode générique avec ?


EDIT: Par exemple, vous devez créer une nouvelle méthode avec cette signature:

private void GenericOnActionExecuted<T>(ActionExecutedContext filterContext) 

Cette méthode aurait le même code que vous avez publié. Ensuite, vous réécrire OnActionExecuted comme ceci:

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 }); 
} 
+0

Je voudrais toujours passer le type en quelque sorte, et c'est la partie que je suis coincé sur: Type de type = typeof (Facture); // Je peux transmettre ceci comme attribut myNewMethod (); // Mais je ne peux pas faire ça? – jeef3

+0

J'ai édité la réponse avec un exemple de code. – Tinister

+0

ah oui, parfait! – jeef3

0

D'après ce que je suis en mesure de comprendre, cela va de difficile, voire impossible que vous essayez de le réaliser.

Si je comprends bien votre question, vous êtes désireux de faire quelque chose comme ceci:

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

Vous pourriez être en mesure d'essayer d'utiliser les informations here, mais je ne sais pas si cela vous aidera dans votre cas spécifique, lorsque vous utilisez des interfaces pour transmettre des informations - comme vous devriez l'être - et qu'il y a toujours le problème de la conversion de type.

+0

Merci andymeadows! Après avoir suivi votre lien, il semble qu'il réponde à ma question de la même manière que les deux autres. Malheureusement, je ne peux attribuer qu'une seule "réponse acceptée", il semble :( – jeef3

+0

Pas de soucis.Les autres commentaires sont BEAUCOUP plus détaillés.C'est heureux que vous l'avez obtenu! – andymeadows

1

Je n'ai jamais utilisé ASP.NET MVC moi-même, mais selon votre explication, je dirais que vous avez deux options. Ces deux solutions nécessitent l'ajout d'une version générique de OnActionExecuted à votre attribut.

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

Vous pouvez réflexion utiliser pour appeler une méthode avec un paramètre de type dynamique:

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

Ou vous pouvez créer une sous-classe d'attribut privé qui connaît sur le type générique au moment de la compilation:

[PagedInvoiceList(PageSize = 2, ListType = typeof (Invoice))] 
public ViewResult List() { ... } 

private class PagedInvoiceListAttribute : PagedListAttribute 
{ 
    public override void OnActionExecuted(ActionExecutedContext filterContext) 
    { 
     DoActionExecuted<Invoice>(filterContext); 
    } 
} 
+0

Merci beaucoup Nathan! C'est la même réponse que Tinister fourni, mais il semble Je ne peux attribuer qu'une seule personne avec une "réponse acceptée" :( – jeef3

Questions connexes