Here is my code:
var json = File.ReadAllText(#"C:\sira.json");
dynamic x = JsonConvert.DeserializeObject<dynamic>(json);
Arac.adli_tip = x.adli_tip;
Arac.aile_hukuku = x.aile_hukuku;
Arac.avrupa_birligi_hukuku = x.avrupa_birligi_hukuku;
Arac.bankacilik_hukuku = x.bankacilik_hukuku;
Arac.bilisim_hukuku = x.bilisim_hukuku;
Arac.borclar_hukuku = x.borclar_hukuku;
Arac.cevre_hukuku = x.cevre_hukuku;
Arac.deniz_ticareti_hukuku = x.deniz_ticareti_hukuku;
Arac.devletler_ozel_hukuku = x.devletler_ozel_hukuku;
Arac.esya_hukuk = x.esya_hukuk;
.
.
.
sira.json is a configuration file about my winforms app.
Here is content of sira.json file:
{
"adli_tip": 15,
"aile_hukuku": 43,
"avrupa_birligi_hukuku": 22,
"bankacilik_hukuku": 10,
.
.
.
"vergi_hukuku": 3
}
I want to get some values from file and set static variables. But these config variables nearly 60.
Is there any way to set static variables programmatically, for example with forecach or while?
EDIT: #subi_speedrunner comment and #T.J.Crowder reply, I searched about Reflection and I coded like this:
But it gives an error. I did not understand why?
Assuming Arac property names match exactly to json property names and Arac properties are public static properties, the following code will work:
using Newtonsoft.Json.Linq;
using System;
namespace ConsoleApplication1
{
public static class Arac
{
public static int adli_tip { get; set; }
public static int aile_hukuku { get; set; }
public static int avrupa_birligi_hukuku { get; set; }
public static int bankacilik_hukuku { get; set; }
public static string string_value {get; set;}
public static DateTime date_value { get; set; }
}
class Program
{
static void Main(string[] args)
{
var json = #"
{
""adli_tip"": 15,
""aile_hukuku"": 43,
""avrupa_birligi_hukuku"": 22,
""bankacilik_hukuku"": 10,
""string_value"": ""some value"",
""date_value"": ""2016-01-24 11:18:00""
}";
JObject arac = JObject.Parse(json);
foreach (var prop in typeof(Arac).GetProperties(System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public))
{
var token = arac.GetValue(prop.Name);
if (token != null)
{
object value = token.ToObject(prop.PropertyType);
prop.SetValue(null, value, null);
}
}
Console.WriteLine("adli_tip {0}", Arac.adli_tip);
Console.WriteLine("aile_hukuku {0}", Arac.aile_hukuku);
Console.WriteLine("avrupa_birligi_hukuku {0}", Arac.avrupa_birligi_hukuku);
Console.WriteLine("bankacilik_hukuku {0}", Arac.bankacilik_hukuku);
Console.WriteLine("string_value {0}", Arac.string_value);
Console.WriteLine("date_value {0}", Arac.date_value);
}
}
}
Note that I use JObject directly instead of JsonConvert.DeserializeObject, this is because JsonConvert.DeserializeObject<dynamic> actually returns a JObject, and I prefer all features of JObject than working with a generic dynamic object.
The code works with integer properties as well as other type of properties as you can see on the sample code.
The following is the relevant code:
JObject arac = JObject.Parse(json);
foreach (var prop in typeof(Arac).GetProperties(BindingFlags.Static | BindingFlags.Public))
{
var token = arac.GetValue(prop.Name);
if (token != null)
{
object value = token.ToObject(prop.PropertyType);
prop.SetValue(null, value, null);
}
}
Yes, you can use reflection, defined in the System.Reflection namespace. Rough sketch:
Get the Type objects for Arac and x
Have an array of the field names you want to process, or use Type object for Arac's GetProperties and/or GetFields methods to get an array of all of its properties/fields (you can specify various features, like whether you only want public ones, etc.)
Loop through the array or the list and for each field:
If you don't already have a FieldInfo/PropertyInfo object from Arac's Type object, use Type#GetField or Type#GetProperty (or one of their relatives) to get it
Get the FieldInfo/PropertyInfo for x's Type object for the same field/property
Use the GetValue method(s) of the FieldInfo/PropertyInfo you got from x's type object to read the value, and the SetValue method(s) of the other FieldInfo/PropertyInfo object to write the value to Arac
Not necessarily saying it's a good idea, since as soon as you put those field names into strings, you make it harder to refactor them with tools, etc., but if the question is "Can I do this?" the answer is "Yes" (and sometimes it's a reasonable choice, there are just trade-offs).
Related
Class Person {
int Id
string Name
string Address
// etc
}
instead of accessing it like Person.Id, Person.Name, Person.Address. I want to access it via index just like Person['Id'], Person['Name']. Is there any codegen or linq conversion for this.
You can use Json.NET's JObject class
Person p = new Person() { Id = 1, Address = "A", Name = "B" };
var obj = JObject.FromObject(p);
Console.WriteLine(obj["Id"]); //1
This is a pure C# implementation:
class Program
{
static void Main(string[] args)
{
Person person = new Person
{
Id = 1,
Name = "test",
Address = "tost"
};
Console.WriteLine(person["Id"]);
person["Id"] = 5;
Console.WriteLine(person["Id"]);
}
}
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public object this[string propertyName]
{
get
{
return this.GetType().GetProperty(propertyName).GetValue(this);
}
set
{
this.GetType().GetProperty(propertyName).SetValue(this, value);
}
}
}
Output:
1
5
Important note:
I would never recommend to use this in a production environment, if you want to use an handly implemented system, atleast you should handle types and properties extractions to avoid consuming more memory than needed and exceeding overheads.
Using reflection and indexers:
public class ExampleClass{
public object this[string name]
{
get
{
var properties = typeof(ExampleClass)
.GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (var property in properties)
{
if (property.Name == name && property.CanRead)
return property.GetValue(this, null);
}
throw new ArgumentException("Can't find property");
}
set {
return;
}
}
}
An indexer won't make data comparison any easier. I suspect the real question is how to handle data in C# the same way Python's DataFrames work. ADO.NET provides the DataTable class since .NET 1.0. It's meant more for database processing than data analysis, altough it does support operations like searching, merging and diffing.
For data anlysis, the new Microsoft.Data.Analysis package provides the DataFrame class.
That said, to read properties by name, you'll have to use Reflection, an expensive operation. One way to make this cheaper is to cache type and property descriptors. Instead of writing the code yourself though, you can use Marc Gravel's FastMember library that does just that. With this, you can create a TypeAccessor or ObjectAccessor type and read properties by name, eg :
var wrapped = ObjectAccessor.Create(obj);
string propName = // something known only at runtime
Console.WriteLine(wrapped[propName]);
If you want to read from multiple objects, you'll need a TypeAccessor :
var accessor = TypeAccessor.Create(type);
string propName = // something known only at runtime
while( /* some loop of data */ )
{
accessor[obj, propName] = rowValue;
}
The library isn't that big. If you aren't allowed to use NuGet packages, you could copy the code into your project.
I have a static class with static fields and a json.
I can deserialize the json into a dynamic object, so I have all the fields and they match exactly the static fields in the class.
How can I use reflection to enumerate the fields and copy the values from the dynamic class into the static class fields?
I can't change the architecture, make it a singleton, etc; it's shared code and the class is going to remain static since it's globally shared settings object used by a shared library.
The solution needs to use reflection since the class evolves over time with new members. Otherwise I could have written a custom deserializer.
Adding more details, but there is really not much:
I have this static class:
static class A
{
static int I;
static string S;
}
and a json matching the fields exactly:
{
"I" : 3,
"S" : "hello"
}
var Data = JsonConvert.Deserialize<dynamic>(...);
I would like to initialize the static fields of class A with the values I deserialized from the json, into a dynamic object.
Another edit:
I came up with something similar to what David wrote, but this is less efficient since I use the deserializer to convert types, so David's solution is better.
here's what I came up with:
foreach (var Destination in typeof(Settings).GetProperties())
{
var Name = Destination.Name;
var T = Destination.PropertyType;
var Value = JsonConvert.DeserializeObject("\"" + JT[Name] + "\"", T);
Destination.SetValue(null, Value);
}
You can do this quite easily by having a matching non-static class, getting the properties of source and destination and looping through each one. For example, assuming we have two classes:
public static class A
{
public static int I { get; set; }
public static string S { get; set; }
}
public class B
{
public int I { get; set; }
public string S { get; set; }
}
We can now do this:
public void MapToStaticClass(B source)
{
var sourceProperties = source.GetType().GetProperties();
//Key thing here is to specify we want the static properties only
var destinationProperties = typeof(A)
.GetProperties(BindingFlags.Public | BindingFlags.Static);
foreach (var prop in sourceProperties)
{
//Find matching property by name
var destinationProp = destinationProperties
.Single(p => p.Name == prop.Name);
//Set the static property value
destinationProp.SetValue(null, prop.GetValue(source));
}
}
Another option is to deserialise to JToken and use that combined with reflection:
var source = JsonConvert.DeserializeObject<JToken>(json);
And then:
public void MapJTokenToStaticClass(JToken source)
{
var destinationProperties = typeof(A)
.GetProperties(BindingFlags.Public | BindingFlags.Static);
foreach (JProperty prop in source)
{
var destinationProp = destinationProperties
.SingleOrDefault(p => p.Name.Equals(prop.Name, StringComparison.OrdinalIgnoreCase));
var value = ((JValue)prop.Value).Value;
//The ChangeType is required because JSON.Net will deserialise
//numbers as long by default
destinationProp.SetValue(null, Convert.ChangeType(value, destinationProp.PropertyType));
}
}
I'm trying to cast dynamic structure which contains a decimal to a concrete class. I haven't been able to find a reasonable solution to that so I'm using "hacky" way by serializing the dynamic structure to JSON and then by deserializing it back to a concrete class. My first question is - Is there a better way to do that?
Actually I've noticed something really strange for me. After doing what I just explained I was trying to get string values out of those decimal values - a.ToString(CultureInfo.InvariantCulture);
To my surprise those strings were different! One was 10 and another 10.0. Can you explain why this happens? During debugging the valus both seem to be the same...
This is my code so you can easily check this:
using System.Globalization;
using Newtonsoft.Json;
using NUnit.Framework;
namespace SimpleFx.UnitTests.UnitTest
{
public class DecimalStruct
{
public DecimalStruct(decimal a)
{
A = a;
}
public decimal A { get; set; }
}
public class DynamicDecimalTest
{
/// <summary>
/// "Hacky" way of casting dynamic object to a concrete class
/// </summary>
public static T Convert<T>(dynamic obj) where T : class
{
var serialized = JsonConvert.SerializeObject(obj);
return JsonConvert.DeserializeObject<T>(serialized);
}
[Test]
public void CastTest()
{
decimal a = 10;
dynamic s1 = new DecimalStruct(a);
var s2 = Convert<DecimalStruct>(s1);
Assert.AreEqual(a, s1.A);
Assert.AreEqual(a, s2.A);
Assert.AreEqual(a.ToString(CultureInfo.InvariantCulture), s1.A.ToString(CultureInfo.InvariantCulture));
Assert.AreEqual(a.ToString(CultureInfo.InvariantCulture), s2.A.ToString(CultureInfo.InvariantCulture)); // this fails because "10.0" is not equal "10"
}
}
}
Please consider the following example to convert dynamic to concrete
var typeName = "YourNamespace.ExampleObj";
object obj = new
{
A = 5,
B = "xx"
};
var props = TypeDescriptor.GetProperties(obj);
Type type = Type.GetType(typeName);
ExampleObj instance = (ExampleObj)Activator.CreateInstance(type);
instance.A = (int)props["A"].GetValue(obj);
instance.B = (string)props["B"].GetValue(obj);
//serialize the instance now...
Lets assume I have the following JSON Object:
{
"Key": "\"QTuY+0m31w2QiZGl4h+W8w==\"",
"Value":
[
"addgroup",
"viewgroup",
"editgroup"
]
}
How can I deserialize the Value part in a C# string[]?
The problem is, string[] is not the only type I have in the Value part, it can be everything, so I need to use dynamic.
I am using JSON.net and when I use the JsonConvert.DeserializeObject method I get a runtime binder exception.
This is the method I use to deserialize:
public async Task<Tuple<string, dynamic>> ReadCachingEntryAsync(string uri) {
var data = tools.ReadEntry(Path.Combine(cacheFolder, uri.Replace("/", "")));
var res = new Tuple<string, dynamic>(string.Empty, null);
if (data != null) {
var dat = JsonConvert.DeserializeObject<KeyValuePair<string, dynamic>>(UTF8Encoding.UTF8.GetString(data));
res = new Tuple<string, dynamic>(dat.Key, dat.Value);
}
return res;
}
The tools.ReadEntry(data) returns a byte[] containing the data, from the binary formatted file.
Here is the class KeyValuePair<K, V>
[Serializable]
internal struct KeyValuePair<K, V> {
public K Key { get; set; }
public V Value { get; set; }
}
You can check if it's a JArray and implement special handling. E.g.
byte[] data = Encoding.UTF8.GetBytes(#"{""Key"": ""Something"", ""Value"": [""test"", ""test 2"", ""test 3""]}");
var dat = JsonConvert.DeserializeObject<KeyValuePair<string, dynamic>>(UTF8Encoding.UTF8.GetString(data));
var value = dat.Value;
if (value is JArray)
{
var arrayType = value[0].Value.GetType().MakeArrayType();
value = value.ToObject(arrayType);
}
var res = new Tuple<string, dynamic>(dat.Key, value);
Just call DeserializeObject<T> replacing T with the type you intend to deserialize the input string into and json.NET will take care of the rest.
string[] json = JsonConvert.DeserializeObject<string[]>(inputString);
EDIT:
Ok, so assuming all of your json is in the form of the example posted in EDIT 3 then waht you really want is;
public class KVPair
{
public string Key { get; set; }
public string[] Value { get; set; }
}
KVPair pair = JsonConvert.DeserializeObject<KVPair>(UTF8Encoding.UTF8.GetString(data));
Now this is fairly static but I'm not sure you actually need dynamic. If you do then you'll want the Value property to be of type object or dynamic. However, if you go that route then you will unfortunately have to deal with this unknown type. I'm really not knowledgeable on the dynamic type so I can't comment on how to deal with it later on but if say for example, the array could contain, ints, floats or strings and you made Value of type object you would have inspect the array later on, determine the underlying type and cast each of the items to that type before you could do anything useful with them. Hope that helps. If you're lucky you'll just be able to use the code I posted above as it's far simpler and is actually type safe.
I have a method, which returns abstract class:
public static object CurrentInfo()
{
// some code here
return new
{
URL = "www.mydomain.com",
User = "Jack",
Age = 20
};
}
When I use the method, I obtain an abstract-class result, so I take it into object (or var) type:
object obj = MyClass.CurrentInfo();
//var obj = MyClass.CurrentInfo(); // I also tried that
I cannot access the properties URL, Age and User from the obj object. If I try followings it cause error.
string myUrl = obj.URL // the same form Age and User
Should I CAST it? But to what...? I would like to exclude the way of creating a new STRUCT.
Create a class with those properties so you can properly access them then the return object can be a strongly-typed class rather than an anonymous one. This way you can access the properties of the object.
such as
public class Info
{
public string URL {get; set;}
public string User {get; set;}
public int Age {get; set;}
}
public static Info CurrentInfo()
{
// some code here
return new Info()
{
URL = "www.mydomain.com",
User = "Jack",
Age = 20
};
}
If you want to retain the anonymous type, which as indicated makes it difficult to work with, then here is a solution for dealing with the returned object:
var obj = CurrentInfo();
System.Type type = obj.GetType();
string url = (string)type.GetProperty("URL").GetValue(obj, null);
You could use the type
Tuple<string, string, int>
This is a named class that represents what you're trying to create, and it's already pre-built into the .NET framework so you don't need to create any new classes or structs.
You would write something like
Tuple<string, string, int> obj = Tuple.Create("www.mydomain.com", "Jack", 20);
See the MSDN documentation for a 3-argument tuple: http://msdn.microsoft.com/en-us/library/dd387150(v=vs.110).aspx