2010-01-21 7 views
5

Je reçois une erreur lorsque j'essaie d'utiliser un paramètre Type lors de la spécification du type pour une méthode générique.C# Type de paramètre en tant que déclaration générique

Error: 'JsonFilter.JsonDataType' is a 'property' but is used like a 'type'

public class JsonFilter : ActionFilterAttribute 
{ 
    public Type JsonDataType { get; set; } 
    public override void OnActionExecuting(ActionExecutingContext filterContext) 
    { 
     ... 
     JavaScriptSerializer jss = new JavaScriptSerializer(); 
     var result = jss.Deserialize<JsonDataType>(inputContent);//Error here 
     ... 

Nouveau Code

... 
JavaScriptSerializer jss = new JavaScriptSerializer(); 
MethodInfo method = jss.GetType() 
       .GetMethod("Deserialize") 
       .MakeGenericMethod(new Type[] { JsonDataType }); 
var result = method.Invoke(jss, new object[] { inputContent }); 
filterContext.ActionParameters[Param] = result; 
... 

Réflexion sauve la journée. Merci @Jason pour l'explication que lorsque le type est spécifié dans le cadre de la méthode générique (< Typename>), alors il est compilé en octets. Considérant que, en tant que propriété, elle peut être de n'importe quel type, déterminable uniquement à l'exécution.

MISE À JOUR

Pour ce problème spécifique, le code suivant est plus concis.

var o = new DataContractJsonSerializer(JsonDataType).ReadObject(
    filterContext.HttpContext.Request.InputStream); 
filterContext.ActionParameters[Param] = o; 
+0

je peux être complètement ici hors de la base, mais il semble que vous voulez que la méthode Deserialize générique de travailler avec un type qui est défini au moment de l'exécution ... Je ne sais pas pense que les génériques fonctionnent de cette façon - ils sont gentils et, bien, génériques au moment de la conception, mais ils se compilent en code spécifique au type ... beurk. mon manque de compréhension montre. Bottom line: Je ne pense pas que ce que vous essayez de faire est possible. Vous ne pouvez pas utiliser Generics avec des types affectés par l'exécution. – Tao

+0

@Tao: Cela peut être fait en utilisant la réflexion. C'est en fait une technique très puissante dans les bonnes circonstances. – jason

Répondre

14

L'erreur

Error: ' JsonFilter.JsonDataType ' is a 'property' but is used like a 'type'

vous dit exactement le problème.

var result = jss.Deserialize<JsonDataType>(inputContent); 

Ici, vous essayez de passer JsonDataType comme un paramètre de type à la méthode générique JavaScriptSerializer.Deserialize<T>

mais ici

public Type JsonDataType { get; set; } 

vous avez déclaré JsonDataType comme une propriété de type Type, mais pas un type. Pour utiliser une méthode générique, vous devez passer un paramètre de type (ou, dans certains cas, laisser le compilateur en déduire un). Par exemple

var result = jss.Deserialize<string>(inputContent); 

serait l'utilisation correcte comme string est un type. Maintenant, si vous voulez absolument utiliser le type représenté par JsonDataType, vous pouvez utiliser la réflexion.

MethodInfo generic = typeof(JavaScriptSerializer).GetMethod("Deserialize") 
               .GetGenericMethodDefinition(); 
MethodInfo closed = generic.MakeGenericMethod(new [] { JsonDataType }); 
closed.Invoke(jss, new object[] { inputContent }); 
+0

Vrai, vrai. C'est une bonne explication du problème. –

+0

Bonjour, je reçois une exception trouvée trouvée ambigu sur la ligne suivante: typeof (JavaScriptSerializer) .GetMethod ("Deserialize") .GetGenericMethodDefinition(); Avez-vous une idée de la cause de l'erreur? :( –

2

Essayez ce quelque chose le long de ces lignes. Je vais le mettre à jour pour votre code en une seconde.

typeof(IDependencyResolver).GetMethod("Resolve", new Type[] { }) 
       .MakeGenericMethod(type) 
       .Invoke(this, null); 

Voici un brouillon pour vous.

typeof(JavaScriptSerializer).GetMethod("Deserialize", new Type[] {} /* param types */) 
    .MakeGenericMethod(JsonDataType).Invoke(jss, /*params*/); 

Fondamentalement, il utilise la réflexion pour invoquer la méthode générique.

+0

Pourquoi le downvote? –

2

Vous ne pouvez pas passer un argument de type générique de cette façon - essayer quelque chose comme ceci:

public class JsonFilter<T> : ActionFilterAttribute 
{ 
    public override void OnActionExecuting(ActionExecutingContext filterContext) 
    { 
     JavaScriptSerializer jss = new JavaScriptSerializer(); 
     var result = jss.Deserialize<T>(inputContent);//Error here 
    } 
} 

Plutôt que de définir le type dans une propriété, faites votre générique de classe JsonFilter afin que vous puissiez passer l'argument de type générique à travers le JavaScriptSerializer.

+0

"Un type générique ne peut pas dériver de 'ActionFilterAttribute' car il s'agit d'une classe d'attributs" ... Impossible de rendre l'attribut générique –

5

Puisque vous ne pouvez pas ajouter un paramètre de type générique à votre classe, vous aurez besoin d'utiliser la réflexion:

public class JsonFilter : ActionFilterAttribute 
{ 
    public Type JsonDataType { get; set; } 

    public override void OnActionExecuting(ActionExecutingContext filterContext) 
    { 
     // ... 
     JavaScriptSerializer jss = new JavaScriptSerializer(); 

     MethodInfo method = jss.GetType() 
           .GetMethod("Deserialize"); 
           .MakeGenericMethod(new Type[] { JsonDataType }); 
     var result = method.Invoke(jss, new object[] { inputContent }); 
     //... 
    } 
} 

originale, réponse incorrecte ...

Pouvez-vous utiliser un paramètre de type générique à la place de la propriété JsonDataType?

public class JsonFilter<TJsonData> : ActionFilterAttribute 
{ 
    public override void OnActionExecuting(ActionExecutingContext filterContext) 
    { 
     // ... 
     JavaScriptSerializer jss = new JavaScriptSerializer(); 
     var result = jss.Deserialize<TJsonData>(inputContent); 
     //... 
    } 
} 

+0

"Un type générique ne peut pas dériver de 'ActionFilterAttribute' car il est une classe d'attributs "... Impossible de rendre l'attribut générique –

+0

@Greg, Dans ce cas, je suppose que la réponse mise à jour, en utilisant la réflexion, est la voie à suivre – LukeH

+0

Oui, bien que, comme vous le savez probablement, dans d'autres cas, ce que vous avez initialement mis en évidence est évidemment meilleur. –

Questions connexes