0

EDIT: All things working now, I was getting the Type.GetType() wrong.

The correct answer is proven correct with 1 change:

.GetMethod("Deserialize", new[] { typeof(string) })

I want to create different types based on some text. I have tried the following without success:

JSON input:

[{"Type":"Book","Details":{"Name":"Book1","Chapter":"1","StartPage":"5","EndPage":"23"}},{"Type":"WebPage","Details":{"Name":"Page1","Url":"sometesturl.com","PageTypeIDs":"1"}}]

Since I do not want to change code every time a new type is added I tought reflection might be the solution.

List<Source> sources = new List<Source>();

dynamic[] items = jsSerializer.Deserialize<dynamic>(validjson);
foreach (var item in items)
        {
            string type = item["Type"];

            string serialized = jsSerializer.Serialize(item["Details"]);

            Type t = Type.GetType(type);
            var instance = createInstanceFromJSON(t, serialized);

            sources.Add(instance);
        }

Will give the following error: 'Cannot be converted from 'System.Type' to 'ProjectManager.Sources'' note that the type is in a seperate DLL called ProjectManager.

Here's the method:

private T createInstanceFromJSON<T>(T type, string json) where T : class
    {
        ConstructorInfo construtorInfo = typeof(T).GetConstructor(new[] { typeof(string) });
        ParameterInfo contructor = construtorInfo.GetParameters()[0];
        object defaultValue = contructor.DefaultValue;

        var item = (T)Activator.CreateInstance(typeof(T), defaultValue);

        item = jsSerializer.Deserialize<T>(json);

        return item;

    }
3
  • You're passing an instance of System.Type into createInstanceFromJSON. Within createInstanceFromJSON, T is now System.Type. Then you're calling typeof(T) on this object, which returns... System.Type. This isn't what you want. T type should be Type type, and you should pass typeof(ProjectManager.Sources) into createInstanceFromJSON. Then, don't do typeof(T).GetConstructor, just do type.GetConstructor. Your code is a bit of a mess, and you should debug it step by step to see what's going on. Commented Jun 2, 2016 at 13:36
  • In addition to that, you could remove the reflection completely since you return the result of the jsSerializer.Deserializer call (in your createInstanceFromJSON) which doesn't depend on the things you do with reflection. Commented Jun 2, 2016 at 13:40
  • You cannot pass a Type as a generic and expect to return something other than a type. Check out this for more information about using reflection with generics stackoverflow.com/questions/266115/… Commented Jun 2, 2016 at 13:40

2 Answers 2

1

I think what you wanted to do is

// no need to make this method generic
private Source createInstanceFromJSON(Type type, string json)
{
    // use reflection to get the method for type "type"
    var deserializeMethod =
        jsSerializer.GetType()
                    .GetMethod("Deserialize")
                    .MakeGenericMethod(new[] { type });

    // invoke the method on the jsSerializer object
    var item = (Source)deserializeMethod.Invoke(jsSerializer, new[] { json });

    return item;
}

Then you can use

string type = item["Type"];
string serialized = jsSerializer.Serialize(item["Details"]);

Type t = Type.GetType(type);
Source instance = createInstanceFromJSON(t, serialized);

sources.Add(instance);
Sign up to request clarification or add additional context in comments.

Comments

0

Your generic parameter T will always have the type System.Type as it is the type describing your Object that you pass as the method parameter.

You have to construct your constructor method differently as you have to call that one already by a reflective call if you want to use the Generic <T> call. Otherwise the compiler will have no idea of what to invoke since T will only be determined T at runtime.

OR

You can salvage your current code using reflection to call that method with the correct type. Remove the first parameter of the method...

private T createInstanceFromJSON<T>(string json) where T : class
{
    ConstructorInfo construtorInfo = typeof(T).GetConstructor(new[] { typeof(string) });
    ParameterInfo contructor = construtorInfo.GetParameters()[0];
    object defaultValue = contructor.DefaultValue;

    var item = (T)Activator.CreateInstance(typeof(T), defaultValue);

    item = jsSerializer.Deserialize<T>(json);

    return item;

}

and then use MethodInfo to call the method with your generic type:

Type t= Type.GetType(type);
MethodInfo method = this.GetType().GetMethod("createInstanceFromJSON", BindingFlags.NonPublic);
method = method.MakeGenericMethod(t);
var instance = method.Invoke(this, serialized);

Although I do not know if that is really helpful to you, it should at least work.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.