Deserialize JSON by passing class as string parameter - c#

Suppose I have this code:
public MessageClass(string _paramJson)
{
string[] Messages = new string[] { "MessageA", "MessageB" };
Messages[0] _model0 = JsonConvert.DeserializeObject<Messages[0]>(paramJson);
Messages[1] _model1 = JsonConvert.DeserializeObject<Messages[1]>(paramJson);
}
I know the above won't work, but All I want is to Deserialize the JSON based on a Type passed as string parameter. ie. MessageA, or MessageB.
Even if I define Messages as List<Type> and then do Messages.Add(typeof(MessageA)); for instance, how do I get the type later and passed it on to DeserializedObject<here-some-type-from-my-list>(paramJson) ?
Any help appreciated.

For this to work, you'd have to use reflection to convert MessageA and MessageB to a Type object, then use reflection to dynamically create an instance of the generic method for that type so you can invoke it.
For the first part, see the Type.GetType method documentation.
var type = Type.GetType("Namespace.Prefix.Message1, AssemblyName");
You can skip that second part by using the non-generic version of DeserializeObject:
var message = JsonConvert.DeserializeObject(paramJson, type);

Related

Construct a generic type through reflection given the type of another object

I'm passing a type to a method and creating an object based on that type. Assume argType is a Type and passed to the method as a parameter.
var assembly = AppDomain.CurrentDomain.GetAssemblies().Single(a => a.GetName().Name == "MyAssembly");
var newType = assembly.GetTypes().SingleOrDefault(x => x.FullName == argType.FullName + "Suffix");
var newObject = Activator.CreateInstance(newType);
This works fine for most objects, but if I pass a type with a generic sub type (e.g. MyClass<MyType>), it fails [Assume the goal is to set newObject to a MyClassSuffix<MyType>].
How could the code above be improved so that generic types (ending with "Suffix") can also be created? I looked at the FullName property for such types which contain substrings like '1[[. I'd rather not do regex parsing to append "Suffix" before these characters begin. I'm thinking there is a better way.
You can use MakeGenericType method if you have instance of both types i.e the generic class and the generic type parameter :
// assuming you have a generic class named Class<>
// taking one generic type parameter
Type generic = typeof(MyClassSuffix<>);
Type typeParameter = typeof(MyClass);
Type genericInstance = generic.MakeGenericType(typeParameter);
and then:
object o = Activator.CreateInstance(genericInstance);
In your case you have generic as newType and you would need to figure out which type you need to pass as type parameter and it should work.
Read the following MSDN docs for detailed instructions on this topic:
https://learn.microsoft.com/en-us/dotnet/framework/reflection-and-codedom/how-to-examine-and-instantiate-generic-types-with-reflection
UDPATE:
You can get generic type parameters too following way
var newType = assembly.GetTypes().SingleOrDefault(x => x.FullName == argType.FullName + "Suffix");
if(newType.IsGenericType)
{
// Get the generic type parameters or type arguments.
Type[] typeParameters = t.GetGenericArguments();
// Construct the type Dictionary<String, Example>.
Type constructed = newType.MakeGenericType(typeParameters);
}
If you are having a closed type then you can instantiate it same way like a normal class. See the following example:
public class GenericClass<Int>
{
}
Now we can generate an instance of it like:
Type t = typeof(GenericClass<int>);
object o = Activator.CreateInstance(y);
Console.WriteLine(o);
DEMO Fiddle

dynamically deserialize json into any object passed in. c#

I'm trying to do is deserialize json into an object in c#. What I want to be able to do is pass any object get it's type and deserialize the json into that particular object using the JSON.Net library. Here are the lines of code.
Object someObject1 = someObject;
string result = await content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<someObject1.GetType()>(result);
The last line throws an exception of
operator '<' cannot be applied to operands of type 'method group'
How do I get the data type in the <> without c# complaining. What do I have to do to make this code work? And what knowledge am I missing?
JsonConvert.DeserializeObject<T> needs a compile-time type. You can't pass it a type in run time as you want to do in question (nothing different than declaring a List<T>). You should either deserialize to a generic json object JObject (or to dynamic) or you should create an instance of an object and fill it with json.
You can use the static method PopulateObject (of course if your object's properties match the json you want to deserialize).
JsonConvert.PopulateObject(result, someObject1 );
You can ignore the generic method and use dynamic:
var myObj = (dynamic)JsonConvert.DeserializeObject(result);
However, if the objects aren't of the same type you'll have a hard time distinguishing between the types and probably hit runtime errors.
For anyone bumping into this problem, the newer versions of Newtonsoft JSON have an overload that takes a type as a second argument and where you can pass a dynamic value without jumping through any hoops:
var myObj = JsonConvert.DeserializeObject(string serializedObject, Type deserializedType);
This is the best way to populate an object's fields given JSON data.
This code belongs in the object itself as a method.
public void PopulateFields(string jsonData)
{
var jsonGraph = JObject.Parse(jsonData);
foreach (var prop in this.GetType().GetProperties())
{
try
{
prop.SetValue(this, fields[prop.Name].ToObject(prop.PropertyType), null);
}
catch (Exception e)
{
// deal with the fact that the given
// json does not contain that property
}
}

C# Loading a type from a string and declaring a List

I have a method that is designed to accept a List in it's declaration as follows:
public class MyHandler
{
public T LookUp<T>()
{
//This method compiles and returns a dynamically typed List
...
}
}
I call this method from elsewhere as such:
MyHandler mh = new MyHandler();
List<AgeGroup> ageGroups = mh.LookUp<List<AgeGroup>>();
This process works great, but I am looking for a way of being able to dynamically load the AgeGroup type from a string.
I have found examples like this, but am not able to work out how to implement it in this case. For example, I have tried the following (and does not compile):
Type t = Assembly.Load("MyNamespace").GetType("MyNamespace.AgeGroup");
List<t> ageGroups = mh.LookUp<List<t>>();
I also tried using typeof(t), but to no avail. Any ideas?
You can construct a generic type at runtime like this:
Type listType = typeof(List<>);
Type typeArg = Assembly.Load("MyNamespace").GetType("MyNamespace.AgeGroup");
listType = listType.MakeGenericType(typeArg);
IList list = (IList)Activator.CreateInstance(listType);
Of course you won't be able to use it as a List<AgeGroup> unless you know the type parameter at compile time. You also won't be able to use Lookup<T> like you did in your example unless you know the type at compile time. You'd have to invoke it like this:
MethodInfo lookupMethod = mh.GetType().GetMethod("LookUp");
lookupMethod = lookupMethod.MakeGenericMethod(listType);
lookupMethod.Invoke(mh, null);

C# Get generic non-array type from generic array type

Given the following function;
void SomeFunction<T>(...){
SomeOtherFunction<T>();
}
This works fine, but sometimes the function fails before T passed is an array type, but it mustn't be an array type. These functions have to do with JSON deserialization of a dictionary, but for some reason it doesn't accept the T array argument when the dictionary has only one entry.
In short, I want to do this
void SomeFunction<T>(...){
try {
SomeOtherFunction<T>();
} catch ( Exception e ){
SomeOtherFunction<T arrayless>();
}
}
I've tried a ton of stuff, and I realize the real problem is somewhere else, but I need to temporary fix this so I can work on a real solution in the deserializer. I tried reflection too using the following method;
MethodInfo method = typeof(JToken).GetMethod("ToObject", System.Type.EmptyTypes);
MethodInfo generic = method.MakeGenericMethod(typeof(T).GetElementType().GetGenericTypeDefinition());
object result = generic.Invoke(valueToken, null);
But that doesn't quite work either.
Thank you!
I am not really sure what you are trying to achieve here, but to get the type of the elements in an array, you have to use Type.GetElementType():
void SomeFunction<T>()
{
var type = typeof(T);
if(type.IsArray)
{
var elementType = type.GetElementType();
var method = typeof(Foo).GetMethod("SomeOtherFunction")
.MakeGenericMethod(elementType);
// invoke method
}
else
foo.SomeOtherFunction<T>(...);
}
If I follow you correctly, you want to call one of two generic functions depending on whether the type of the object is an array or not.
How about:
if (typeof(T).ImplementsInterface(typeof(IEnumerable)))
someFunction<T>();
else
someOtherFunction<T>();

C# Language: How to get type of bound but open Generic class?

Let's say I have such a generic class
public class XClass<T, U>
{
public void MethodA<V>(){}
}
How could I get the type of
XClass<int,>
not hard-coded, not limiting to MakeGenericType method as below.
------ detailed elaboration below using MakeGenericType ------
I can get the type of the unbound and open class "XClass<,>" and its open method:
var type = typeof(XClass<,>);
Console.WriteLine(String.Format("Type ZClass<,>: \t generic? {0} \t open? {1}"
, type.IsGenericType, type.IsGenericTypeDefinition));
var method = type.GetMethod("MethodA");
Console.WriteLine(String.Format("Method MethodA<>: \t generic? {0} \t open? {1}"
, method.IsGenericMethod, method.IsGenericMethodDefinition));
Also, I can get the type of full closed class
XClass <int, char>
and its close method:
var type = typeof(XClass<,>);
var method = type.GetMethod("MethodA");
var fullType = method.DeclaringType.MakeGenericType(new[]{typeof(int), typeof(char)});
Console.WriteLine(String.Format("Type ZClass<int,char>: \t generic? {0} \t open? {1}"
, fullType.IsGenericType, fullType.IsGenericTypeDefinition));
var fullTypeOpenMethod = fullType.GetMethod("MethodA");
var fullMethod = fullTypeOpenMethod.MakeGenericMethod(typeof(string));
Console.WriteLine(String.Format("Method MethodA<String>:\t generic? {0} \t open? {1}"
, fullMethod.IsGenericMethod, fullMethod.IsGenericMethodDefinition));
Now, How can I get the type of bound but open class
XClass<int, >
and its method?
var type = typeof(XClass<,>);
var method = type.GetMethod("MethodA");
Type [] types = new Type[2];
types[0] = typeof(int);
types[1] = null; // what shall i put here?
var halffullType = method.DeclaringType.MakeGenericType(types);
If I put types[1] as null, an ArgumentNullException exception will throw "Value cannot be null".
What should I do?
What you are proposing to do is impossible and also will not really help you.
Impossible because...
The documentation states (emphasis mine) that
Types constructed with MakeGenericType can be open, that is, some of
their type arguments can be type parameters of enclosing generic
methods or types.
This means that you cannot make a Type object representing XClass<int,>. What you can do is:
class Outer<TOuter>
{
class XClass<T, U> {}
}
In this situation, you can make a Type object representing Outer<TOuter>.XClass<int, TOuter>. But there needs to be an enclosing generic class.
Not useful because...
The documentation also states (referring to a similar example to the above) that:
A constructed type such as Base is useful when emitting code,
but you cannot call the MakeGenericType method on this type because it
is not a generic type definition. To create a closed constructed type
that can be instantiated, first call the GetGenericTypeDefinition
method to get a Type object representing the generic type definition
and then call MakeGenericType with the desired type arguments.
Which means that if you have
Type myType = ... // represents Outer<TOuter>.XClass<int, TOuter>
Then to get a Type for XClass<int, string> you would first need to call myType.GetGenericTypeDefinition() (thus losing the int information) and then call MakeGenericType to put it back in (along with the string type parameter). So it's like one step back and two steps forward.
Alternatives
You might want to consider storing the type parameter types for XClass in a separate data structure (e.g. a Type[]) for as long as not all type parameters are known to you, and then create the closed generic type in one go after you have collected all of them.
You can also package all this into a small helper class for convenience:
class GenericTypeDescription
{
private readonly Type openGenericType;
private readonly Type[] typeParameters;
public GenericTypeDescription(Type openGenericType)
{
// add checks for openGenericType actually being what it says here
this.openGenericType = openGenericType;
this.typeParameters = new Type[openGenericType.GetGenericArguments().Length];
}
public void SetTypeParameter(int index, Type type) {
// add error handling to taste
this.typeParameters[index] = type;
}
public Type ConstructGenericType() {
// add error handling to taste
return this.openGenericType.MakeGenericType(this.typeParameters);
}
}
No, this isn't possible.
See my similar question: Does .Net support curried generics?
This is possible, when you feed MakeGenericType with its own generic arguments.
var type = typeof(XClass<,>);
var method = type.GetMethod("MethodA");
Type[] types = new Type[2];
types[0] = typeof(int);
types[1] = type.GetGenericArguments()[1]; // Use the open parameter type
var openConstructedType = type.MakeGenericType(types);
This will populate openConstructedType with a Type of XClass<int,U>.
Note that the type will have ContainsGenericParameters, so it won't be constructable, and there's no way to populate the open parameters.
I don't think that this is possible without inheriting from the class.
What you seem to be trying is to basically do this via reflection:
typeof(XClass<int,>)
This would be half-closed... and only possible by inheritance AFAIK:
class XClassInt<U>: XClass<int, U> {}
This second code allows you to get typeof(XClassInt<>).BaseType which is kind of what you want. However, in that case the second type argument for XClass<,> is not null but actually U (the type argument coming from XClassInt<>).
See also this MSDN page.
Edit: Here's my testbed for this:
public class C1<A,B> {}
public class C2<B>: C1<int, B> {}
[...]
Type baseType = typeof(C2<>).BaseType;
WL(baseType);
WL(baseType.GetGenericArguments()[0]);
Type arg1 = baseType.GetGenericArguments()[1];
WL(arg1);
WL(arg1.DeclaringType);
WL(arg1.GenericParameterPosition);
WL(arg1.IsGenericParameter);
Running this yields:
C1`2[System.Int32,B]
System.Int32
B
C2`1[B]
0
True
However, as I said, I believe this is only possible because the base type is closed with the generic type argument of the open generic type C2.

Categories