开发者

C# Type parameter as Generic declaration

I am getting an error when trying to use a Type par开发者_StackOverflow社区ameter when specifying the Type for a generic method.

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

New 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;
...

Reflection saves the day. Thanks @Jason for the explanation that when type is specified as part of generic method ( <Typename> ), then it gets compiled into bytes. Whereas when as property, it can be any type, only determinable at runtime.

UPDATE

For this specific problem, the following code is more concise.

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


The error

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

is telling you exactly the problem.

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

Here, you are trying to pass JsonDataType as a type parameter to the generic method JavaScriptSerializer.Deserialize<T>

but here

public Type JsonDataType { get; set; }

you declared JsonDataType as a property of type Type, but not as a type. To use a generic method you need to pass a type parameter (or, in some cases, let the compiler infer one). For example

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

would be correct usage as string is a type.

Now, if you absolutely want to use the type that is represented by JsonDataType you can use reflection.

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


Since you can't add a generic type parameter to your class then you'll need to use reflection:

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 });
        //...
    }
}

Original, incorrect answer...

Can you use a generic type parameter instead of the JsonDataType property?

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


Try this something along these lines. I'll update it for your code in a sec.

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

Here is a rough draft for you.

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

Basically it uses reflection to invoke the generic method.


You cannot pass a generic type argument in this way - try something like this:

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

Rather than setting the type in a property, make your JsonFilter class generic so that you can pass the generic type argument through to the JavaScriptSerializer.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜