Can I access fields of an Object in C# - c#

I am using Newtonsoft.Json.JsonConvert.DeserializeObject(string str) to translate a string into a .Net Object. The real type of this string can be multiple, and there's no other information to indicate the type of this string. But I can confirm that the string message is a derived class object of a common class like Message, and fields in Message can however tell the real type, Message has a field like int type. The string is MessageA or MessageB or whatever all with a different type.
If I translate it into an Object, I can saw in the visual studio debugger that this Object have exactly the fields described in the Json string. But I cant access these fields. And cast this Object into a Message will failed with a bad cast.
What I am doing now is first translate the string into a Message and to see the type, then I translate again. It's not preferred. So can I just translate it into something that I can read all of the data? Another option is Dictionary, but I have some numerical fields. Any other suggestions?

JsonConvert.DeserializeObject(string str), when used on a JSON object, returns a JObject. You can use this directly (e.g. use DeserializeObject<JObject> to explicitly type it), or as a dynamic, to access its properties, e.g.
var data = #"{""type"": 1, ""otherProperty"": ""Hello!""}";
dynamic obj = JsonConvert.DeserializeObject(data);
if (obj.type == 1)
{
Console.WriteLine(obj.otherProperty); // prints Hello!
}
Also, you mention numeric fields as being a problem with working with a dictionary, but if you make it a Dictionary<string, dynamic> you might find it easier to work with:
var data = #"{""type"": 2, ""otherProperty"": 5}";
var dict = JsonConvert.DeserializeObject<Dictionary<string, dynamic>>(data);
if (dict["type"] == 2)
{
int i = (int)dict["otherProperty"]; // type is long, so cast is required if you want an int
Console.WriteLine(i); // prints 5
}

Related

Json.net DeserializeAnonymousType returns BigInteger instead of UInt64

Suppose we have the following code:
Type t = typeof(UInt64);
var def = Activator.CreateInstance(t);
Console.WriteLine(def.GetType());
string json = "18446744073709551615";
object parsedObject = JsonConvert.DeserializeAnonymousType(json, def);
Console.WriteLine(parsedObject.GetType());
The output is:
System.UInt64
System.Numerics.BigInteger
Since I explicitly fed DeserializeAnonymousType with def, type of which is UInt64, I would expect also UInt64 as an output, especially since 18446744073709551615 is a valid UInt64 value (max value, granted, but I checked also with 18446744073709551614, it is same).
Why is it so? I checked Newtonsoft Github issues, and found nothing (at least, not in open issues).
How can I force the correct type which I know in advance (dynamically, I have only System.Type)? Obviously, if it happens only for UInt64 I can make a check and cast explicitly.
Your problem is that JsonConvert.DeserializeAnonymousType<T>(string value, T anonymousTypeObject) doesn't quite do what you expect. It doesn't deserialize the JSON string to the actual type of the T anonymousTypeObject argument. It deserializes the JSON string to the declared type of the argument -- which in your case, is object.
This can be seen from the reference source:
public static T DeserializeAnonymousType<T>(string value, T anonymousTypeObject)
{
return DeserializeObject<T>(value);
}
The T anonymousTypeObject is never actually used. Instead the target type is entirely specified via type inference when the call to DeserializeAnonymousType is made -- specifically from the declared type of the variable def in your code. But def is implicitly declared to be an object, because that is what Activator.CreateInstance(Type type) is declared to return. Thus object is what Json.NET deserializes the JSON as -- some .Net type sufficient to capture the incoming JSON. As BigInteger is sufficient to capture the incoming JSON, Newtonsoft happens to choose that type instead of Uint64.
if you want to force Json.NET to deserialize to the actual, concrete type of a specific object, use JsonConvert.DeserializeObject(string value,Type type):
object parsedObject = JsonConvert.DeserializeObject(json, def.GetType());
Demo fiddle here.
I used this example and thought that I would advance it to a list of classes:
List<_class> listOfClasses = new List<_class>();
var content = response.Content.ReadAsStringAsync().Result;
object parsedObject = JsonConvert.DeserializeAnonymousType(content, Activator.CreateInstance(typeof(_class)));
var _listOfClasses = JsonConvert.DeserializeObject<List<_class>>(parsedObject.ToString());
listOfClasses = _listOfClasses;
What this does is to consume a list of TEntity 's from an API, and then parse it back to the class it's matched against in the consumer

Is there a way to place enum type in variable for later casting?

I'm written a function that given an object's name and a value, returns the text names of the bits. These bit names are defined in an various enums. Here is the essence of my function.
string BitName(string object_name, long bit_value) {
string bit_name="";
switch(object_name) {
case "STATUS_WORD" :
bit_name = ((eStatusWord)bit_value).ToString();
break;
case "TRAJ_STATUS" :
bit_name = ((eTrajectoryStatus)bit_value).ToString();
break;
}
return bit_name;
}
This simple approach worked, but now there are more actions that will create a lot of replicated code.
At minimum I'd like to place the enum type into a variable and use that for casting. Something like this:
Type my_type = eStatusWord;
bit_name = ((my_type)bit_value).ToString();
// addition actions that are type dependent
If its possible then a Dictionary could replace the switch statement.
Enum.ToObject allows you to dynamically reconstruct an enum by knowing the type.
From there, you can use a Dictionary<string, Type to map the string to the enum type, and reconstruct the value:
bit_name = Enum.ToObject(dictionary[object_name], bit_value).ToString();
To populate the dictionary, use typeof:
dictionary.Add("STATUS_WORD", typeof(eStatusWord));

Parse an object to a string representation c#

I'm trying to parse my variable to its string representation typeName.
string typeName = property.PropertyType.ToString();
var propertyItem = (typeName)property.GetValue(templateData, null);
The string typeName should be the 'Type' of the property I have in my Model so somehow i want to parse it to that type. (at this moment it is List(InvoiceModel), but this may vary)
I hope this is enough information, otherwise please notify me. Thanks in advance.
property.GetValue returns the required object. From your code sample it seems that you don't know the object's type at compile time.
It is not possible to cast that object using (typename), and there is no use, because still you won't know the real type at compile time.
What you probably want to do is to use dynamic:
dynamic propertyItem = property.GetValue(templateData, null);
I think what you are looking for is property.GetType().ToString();
though you can't just put the varable in brackets to convert you need to use reflection to create the type
That said this entire idea is a bad idea, from the look of your code i think your trying to create some form of MetaData, if so then i would use an Enum to define your allowed datatypes, and i would only allow the simplest ones int, double, string, datetime etc and possibly an array's of such
in that case you would then do,
if(Property.Type == AllowedTyoes.String)
{
string stringval = Property.Value as string;
//use the string for a string safe function
}
if(Property.Type == AllowedTyoes.Int)
{
string stringval = Property.Value as string;
int tmp;
if(int.TryParse(stringval,out tmp))
{
//use the int for a int safe function
}
}

How to generalize a generic method to parse text and assign to a list of variables for different number of variables?

I need to read a tab (or comma) separated text and assign them to a list of built-in variables (int, char, string, etc. but not object). I want to handle this with a generic method. Here is the working code I am using for the case with three variables.
public static void ReadVariablesFromString<T0, T1, T2>(out T0 input0, out T1 input1, out T2 input2, string stringIn, char[] separators)
{
string[] stringParts = stringIn.Split(separators);
input0 = ConvertTo<T0>(stringParts[0]);
input1 = ConvertTo<T1>(stringParts[1]);
input2 = ConvertTo<T2>(stringParts[2]);
}
public static T ConvertTo<T>(object value)
{
return (T)Convert.ChangeType(value, typeof(T));
}
When I want to assign the tab separated text to three variables of different type, this is what I use:
string str = "a\t123\tbcd";
char var1;
int var2;
string var3;
char[] separators = { '\t' };
ReadVariablesFromString(out var1, out var2, out var3, str, separators);
Is there a way to generalize this model for different number of variables? Is it possible to write a generic method that accepts different number of variables for this specific case?
One of the other solution might be writing this method for a variable list with different types. Instead of passing variables one by one, is there a way to pass them in a list?
No, in C# you can not send array of variable references.
But what you can do is create a class with some properties, and then use reflection to fill them.
See Enumerating through an object's properties (string) in C# and Set object property using reflection
and How to dynamically cast an object of type string to an object of type T on some details.
I suggest you return a List
List<object> variables = ReadVariablesFromString(str, separators);
Where each entry in the list will be the values your parse from the input string, for example
variables.ElementAt(0) will be 'a'
Since the type of the list is 'object', you can store any data type in there, since each type ultimately inherits from object anyway. You would need to cast the data when you need to use it though
char letter = (char)variables.ElementAt(0)
But you must be doing something similar already, otherwise how would you know which variable to put in each incoming out parameter.
Doing this means you have more flexibility in the amount of variables you can return from ReadVariablesFromString()

How "safe" are Anonymous Types and Reflection together?

I guess this could also be asked as to how long the created type name is attached to an anonymous type. Here's the issue:
A blog had something like this:
var anonymousMagic = new {test.UserName};
lblShowText.Text = lblShowText
.Text
.Format("{UserName}", test);
As sort of a wish list and a couple ways to go at it. Being bored and adventurous I took to creating an string extension method that could handle this:
var anonymousMagic = new {test.UserName, test.UserID};
lblShowText.Text = "{UserName} is user number {UserID}"
.FormatAdvanced(anonymousMagic);
With the idea that I would get the property info from the anonymous type and match that to the bracketted strings. Now with property info comes reflection, so I would want to save the property info the first time the type came through so that I wouldn't have to get it again. So I did something like this:
public static String FormatAdvanced(this String stringToFormat, Object source)
{
Dictionary<String, PropertyInfo> info;
Type test;
String typeName;
//
currentType = source.GetType();
typeName = currentType.Name;
//
//info list is a static list for the class holding this method
if (infoList == null)
{
infoList = new Dictionary<String, Dictionary<String, PropertyInfo>>();
}
//
if (infoList.ContainsKey(typeName))
{
info = infoList[typeName];
}
else
{
info = test.GetProperties()
.ToDictionary(item => item.Name);
infoList.Add(typeName, info);
}
//
foreach (var propertyInfoPair in info)
{
String currentKey;
String replacement;
replacement = propertyInfoPair.Value.GetValue(source, null).ToString();
currentKey = propertyInfoPair.Key;
if (stringToFormat.Contains("{" + currentKey + "}"))
{
stringToFormat = stringToFormat
.Replace("{" + currentKey + "}", replacement);
}
}
//
return stringToFormat;
}
Now in testing, it seems to keep the name it created for the anonymous type so that the second time through it doesn't get the property info off the type but off the dictionary.
If multiple people are hitting this method at the same time, is it pretty much going to work in a Session like fassion; IE the names of the types will be specific to each instance of the program? Or would it be even worse than that? At what point does that name get chucked and overwritten?
It never does. The type is generated at compile-time and you can consider it constant and unique throughout the life of the app-domain.
I question the value of this function though. The obvious first reason is because you don't have much of the functionality of the Format method on the String class (no escape for brackets, no formatting of values in the brackets, etc, etc).
The second is that it basically links the format string to the type being passed in, so they are not swapped out easily. If I had two classes which had the same conceptual value, but different properties naming it, I have to change my format string to display it with your method to compensate for the fact that the property name is embedded in the format string.
Anonymous types are generated at compile time, and so the reflection names should be static as long as you don't re-compile the assembly.
There is a detailed post here that describes the names, but I believe what you are doing is safe.
I have two things to say, but this isn't really an answer.
First of all, the Dictionary doesn't have to have a string key; the key could be the actual type. i.e. it could be a Dictionary<Type, Dictionary<String, PropertyInfo>>. That would be faster because you don't have to get the type name, and less error prone - what if I send that method two non-anonymous types with the same name but different namespaces?
Second, you should read Phil Haack's recent blog post about this subject. It contains a full implementation of such a method.

Categories

Resources