I am trying to build a solution fitting with the problem of not knowing what kind of Setting type I am dealing with.
I got a Dictionary<string, Type> (which I initially wanted to make <string, class> but that didn't work)
that I want to fill with the setting code and the type of class attached to it i.e.
{ "person_customField", typeof(CustomFieldModel) }
Why I want to do this is because I have a field in my database filled with json data that should be deserialized to a List<> but I don't know what kind of setting it is until I get the object from the database. I can use the Code field to detemine what type it is (person_CustomField should use the CustomFieldModel class, but emailSetting should use EmailSettingModel to match parameters to.
Is there a way to successfully make this statement work with?
JsonConvert.DeserializeObject<List<SettingTypes[record.SettingCode]>>(record.SettingValues).ToList<ISetting>()
Or should I go a different route
Code Sample:
public static readonly Dictionary<string, Type> SettingTypes = new Dictionary<string, Type>()
{
{ "person_CustomFields", typeof(CustomFieldModel)},
};
public static TenantSettingEdit ConvertToTenantSettingEdit(this T_TenantSetting rec)
{
var test = SettingTypes[rec.TENS_Code];
TenantSettingEdit item = new TenantSettingEdit()
{
IDToken = rec.TENS_TenantSettingID.toVirtualGuid().ToString(),
Code = rec.TENS_Code,
Settings = JsonConvert.DeserializeObject<List<SettingTypes[rec.TENS_Code]>>(rec.TENS_Setting).ToList<ITenantSetting>(),
IsActive = rec.TENS_ActiveRec,
};
return item;
}
(I have done this before with PHP but I am not sure if this is even remotely possible with C#)
Why I want to do this is because I have a field in my database filled
with json data that should be deserialized to a List<> but I don't
know what kind of setting it is until I get the object from the
database.
If you're using Json.Net for JSON serialization/deserialization you can use the TypeNameHandling property to embed Type information in the resulting JSON. That JSON can the be deserialized by Json.Net without additional information. If it is necessary to map custom values to the types instead of the automatically generated ones you can use a SerializationBinder (check out this answer).
If none of those help you, you can still fall back to reflection in the way M Kloster describes.
You cannot use a variable as the type parameter in the code, no. What you need to do is to generate the type-specific method by reflection:
var genericMethod = ((Func<string, int>)Json.DeserializeObject<int>).Method.GetGenericMethodDefinition();
var boundMethod = genericMethod.MakeGenericMethod(SettingTypes[record.SettingCode]);
var result = boundMethod.Invoke(null, rec.TENS_Setting)...
I'm trying to write a generic utility for use via COM from outside .NET (/skip long story). Anyway, I'm trying to add properties to an ExpandoObject and I need to get PropertyInfo structure back to pass to another routine.
using System.Collections.Generic;
using System.Diagnostics;
using System.Dynamic;
using System.Reflection;
public class ExpandoTest
{
public string testThis(string cVariable)
{
string cOut = "";
ExpandoObject oRec = new ExpandoObject { };
IDictionary<string, object> oDict = (IDictionary<string, object>)oRec;
oDict.Add(cVariable, "Test");
Trace.WriteLine(cVariable);
Trace.WriteLine(oDict[cVariable]);
PropertyInfo thisProp = oRec.GetType().GetProperty(cVariable);
if (thisProp != null)
{
cOut= "Got a property :)";
}
return cOut;
}
}
Why do I always get a null in in thisProp? I clearly don't understand but I've been staring at it for a day and I'm not getting anywhere. All help/criticism thankfully accepted!
While using an ExpandoObject it might look like you can add properties at runtime, it won't actually do that at the CLR level. That's why using reflection to get the property you added at runtime won't work.
It helps to think of an ExpandoObject as a dictionary mapping strings to objects. When you treat an ExpandoObject as a dynamic variable any invocation of a property gets routed to that dictionary.
dynamic exp = new ExpandoObject();
exp.A = "123";
The actual invocation is quite complex and involves the DLR, but its effect is the same as writing
((IDictionary<string, object>)exp)["A"] = "123";
This also only works when using dynamic. A strongly typed version of the code above results in a compile-time error.
var exp = new ExpandoObject();
exp.A = "123"; // compile-time error
The actual implementation of ExpandoObject can be found here.
I have a project in which I have some assemblies which implement an abstract class.
Each assembly has a public enum called ResultEnum.
This ResultEnum's value is stored in a database as an int.
I have another web project which displays some info, and I want it to also display this int's string representation - the name of the corresponding value from the ResultEnum.
What I want to do is, using MEF, load all the relevant assemblies (no problem here), search for this enum using reflection (no problem here also) and then to store the enum in some way, and cache it in order to avoid all this process the next time I want to convert the int from the database to the string representation (and the other way around if necessary) since I have several thousands of records in my db table.
AggregateCatalog catalog = new AggregateCatalog();
catalog.Catalogs.Add(new DirectoryCatalog(path));
_container = new CompositionContainer(catalog);
try
{
_container.ComposeParts(this);
}
catch (CompositionException compositionException)
{
Console.WriteLine(compositionException.ToString());
}
foreach (var task in myTasks)
{
TaskAbstract instance = (TaskAbstract)task.CreateExport().Value;
MemberInfo[] infos = instance.GetType().GetMembers(BindingFlags.Public | BindingFlags.Static);
foreach (MemberInfo member in infos.Where(x => x.Name.Equals("ResultEnum")))
{
Console.WriteLine(member);
}
}
What do you suggest the next move should be?
How should I store/cache it?
Thanks
In addition to #Thomas's answer:
As using reflection you can get exact int value from a property, the name for that concrete value could be gotten using the next expression:
var enumValueName = Enum.GetName(member.GetType(), member.GetValue(instance));
UPD
I really missed that you reflect MemberInfos. To apply my solution you can update you reflection this way:
foreach (var task in myTasks)
{
TaskAbstract instance = (TaskAbstract)task.CreateExport().Value;
// Reflect properties, not all members
PropertyInfo[] infos = instance.GetType().GetProperties(BindingFlags.Public | BindingFlags.Static);
foreach (PropertyInfo prop in infos.Where(x => x.Name.Equals("ResultEnum")))
{
var enumValueName = Enum.GetName(prop.GetType(), prop.GetValue(instance));
}
}
Or you could cast MemberInfo to PropertyInfo.
One approach to solving this problem is to consider using a subclassable enums technique (also sometimes referred to as a polymorphic enum).
I wrote a couple of generic classes specifically to support these kinds of types which you can read about here. Also, a proposal has been submitted to the Roslyn compiler team on Github to add support for these types of enums to C#.
Here is an example of a set of subclassable enums that have two underlying types, string and integer, using the classes from my project:
public sealed class Status : StringIntegerEnum<Status>
{
public static readonly Status Active = new Status("active", 1);
public static readonly Status Inactive = new Status("inactive", 0);
private Status(string status, int statusCode) : base(status, statusCode) {}
}
Note that the string value is not the same as the constant name itself, which allows you to have underlying string values with characters that violate the normal naming conventions in C#.
The StringIntegerEnum<tStringIntegerEnum> base class provides .AllValues, .AllNaturalValues and .AllStringValues static methods that you can use to enumerate the list of enum values or both types of their underlying values.
From your comment:
I agree, But question is how do I iterate over the values and names of the enumerator
I assume you mean "enumeration", not "enumerator". You can use the Enum.GetValues method:
var valuesToNames =
Enum.GetValues(enumType)
.Cast<object>()
.ToDictionary(o => (int)o, o => Enum.GetName(enumType, o));
And, is there a better solution than a dictionary
Better how? I think a dictionary is a fine solution; is there any reason why you would want something else?
This is how i've written the code eventually:
resultEnumsForTasks = new Dictionary<string, Dictionary<UInt16, string>>();
foreach (var task in myTasks)
{
Dictionary<UInt16, string> _enum = new Dictionary<UInt16,string>();
TaskAbstract instance = (TaskAbstract)task.CreateExport().Value;
MemberInfo resultEnum = instance.GetType().GetMember("ResultEnum").FirstOrDefault();
if (resultEnum == null)
continue;
string[] names = Enum.GetNames(resultEnum as Type);
IList<int> vals = (IList<int>)Enum.GetValues(resultEnum as Type);
for (int i = 0; i < names.Length; i++)
{
_enum.Add(Convert.ToUInt16(vals[i]), names[i]);
}
resultEnumsForTasks.Add(instance.GetType().Name, _enum);
}
It's very similar to #n.turakulov 's solution, however his solution didn't work for me since I got an empty list of PropertyInfo for some reason...
Thanks for everyone who assisted!
I am developing a windows 8 app, and i have some javascript that stores a serialized object into roaming settings, i.e:
var object = [{"id":1}, {"id":2}]
roamingSettings.values["example"] = JSON.stringify(object);
I also i have a c# part to the application (for running a background task), that needs to read that JSON, and turn it into an object so i can iterate over it. And this is where i am having some issues, i am using JSON.NET to do the work, but every thing i turn turns up with an error:
// this looks like "[{\"id\":1},{\"id\":2}]"
string exampleJSON = roaming.Values["example"].ToString();
// dont know if this is correct:
List<string> example = JsonConvert.DeserializeObject<List<string>>(exampleJSON );
That give an error of:
Error reading string. Unexpected token: StartObject. Path '[0]', line 1, position 2.
So i am at a loss of what to do, i have been working on it for last few hours, and i am quite unfamiliar with c#, so resorting to the help of stackoverflow ;D
Thanks in advance for any help :)
Andy
Json.Net has a nice method DeserializeAnonymousType. No need to declare a temporary class.
string json = "[{\"id\":1},{\"id\":2}]";
var anonymous = new []{new{id=0}};
anonymous = JsonConvert.DeserializeAnonymousType(json,anonymous);
foreach (var item in anonymous)
{
Console.WriteLine(item.id);
}
You can even use the dynamic keyword
dynamic dynObj = JsonConvert.DeserializeObject(json);
foreach (var item in dynObj)
{
Console.WriteLine(item.id);
}
You are trying to parse your JSON array into a List of strings, which doesn't work. The JSON object you provide is actually a list of objects containing an integer property called 'id'.
Perhaps try creating a class (say, MyClass) with just that property, and deserialize into List.
Your json containts a collection of objects with an id property, something like this:
class IdObject {
public int id { get; set; }
}
You could then do:
JsonConvert.DeserializeObject<List<IdObject>>(exampleJSON);
Because the IdObject class has a property id to match your json serialized value, it will be mapped back.
I'd like to access the value of a dynamic c# property with a string:
dynamic d = new { value1 = "some", value2 = "random", value3 = "value" };
How can I get the value of d.value2 ("random") if I only have "value2" as a string? In javascript, I could do d["value2"] to access the value ("random"), but I'm not sure how to do this with c# and reflection. The closest I've come is this:
d.GetType().GetProperty("value2") ... but I don't know how to get the actual value from that.
As always, thanks for your help!
Once you have your PropertyInfo (from GetProperty), you need to call GetValue and pass in the instance that you want to get the value from. In your case:
d.GetType().GetProperty("value2").GetValue(d, null);
public static object GetProperty(object target, string name)
{
var site = System.Runtime.CompilerServices.CallSite<Func<System.Runtime.CompilerServices.CallSite, object, object>>.Create(Microsoft.CSharp.RuntimeBinder.Binder.GetMember(0, name, target.GetType(), new[]{Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create(0,null)}));
return site.Target(site, target);
}
Add reference to Microsoft.CSharp. Works also for dynamic types and private properties and fields.
Edit: While this approach works, there is almost 20× faster method from the Microsoft.VisualBasic.dll assembly:
public static object GetProperty(object target, string name)
{
return Microsoft.VisualBasic.CompilerServices.Versioned.CallByName(target, name, CallType.Get);
}
Dynamitey is an open source .net std library, that let's you call it like the dynamic keyword, but using the a string for the property name rather than the compiler doing it for you, and it ends up being equal to reflection speedwise (which is not nearly as fast as using the dynamic keyword, but this is due to the extra overhead of caching dynamically, where the compiler caches statically).
Dynamic.InvokeGet(d,"value2");
The easiest method for obtaining both a setter and a getter for a property which works for any type including dynamic and ExpandoObject is to use FastMember which also happens to be the fastest method around (it uses Emit).
You can either get a TypeAccessor based on a given type or an ObjectAccessor based of an instance of a given type.
Example:
var staticData = new Test { Id = 1, Name = "France" };
var objAccessor = ObjectAccessor.Create(staticData);
objAccessor["Id"].Should().Be(1);
objAccessor["Name"].Should().Be("France");
var anonymous = new { Id = 2, Name = "Hilton" };
objAccessor = ObjectAccessor.Create(anonymous);
objAccessor["Id"].Should().Be(2);
objAccessor["Name"].Should().Be("Hilton");
dynamic expando = new ExpandoObject();
expando.Id = 3;
expando.Name = "Monica";
objAccessor = ObjectAccessor.Create(expando);
objAccessor["Id"].Should().Be(3);
objAccessor["Name"].Should().Be("Monica");
var typeAccessor = TypeAccessor.Create(staticData.GetType());
typeAccessor[staticData, "Id"].Should().Be(1);
typeAccessor[staticData, "Name"].Should().Be("France");
typeAccessor = TypeAccessor.Create(anonymous.GetType());
typeAccessor[anonymous, "Id"].Should().Be(2);
typeAccessor[anonymous, "Name"].Should().Be("Hilton");
typeAccessor = TypeAccessor.Create(expando.GetType());
((int)typeAccessor[expando, "Id"]).Should().Be(3);
((string)typeAccessor[expando, "Name"]).Should().Be("Monica");
Much of the time when you ask for a dynamic object, you get an ExpandoObject (not in the question's anonymous-but-statically-typed example above, but you mention JavaScript and my chosen JSON parser JsonFx, for one, generates ExpandoObjects).
If your dynamic is in fact an ExpandoObject, you can avoid reflection by casting it to IDictionary, as described at http://msdn.microsoft.com/en-gb/library/system.dynamic.expandoobject.aspx.
Once you've cast to IDictionary, you have access to useful methods like .Item and .ContainsKey
The GetProperty/GetValue does not work for Json data, it always generate a null exception, however, you may try this approach:
Serialize your object using JsonConvert:
var z = Newtonsoft.Json.JsonConvert.DeserializeObject(Convert.ToString(request));
Then access it directly casting it back to string:
var pn = (string)z["DynamicFieldName"];
It may work straight applying the Convert.ToString(request)["DynamicFieldName"], however I haven't tested.
d.GetType().GetProperty("value2")
returns a PropertyInfo object.
So then do
propertyInfo.GetValue(d)
To get properties from dynamic doc
when .GetType() returns null, try this:
var keyValuePairs = ((System.Collections.Generic.IDictionary<string, object>)doc);
var val = keyValuePairs["propertyName"].ToObject<YourModel>;
This is the way i ve got the value of a property value of a dinamic:
public dynamic Post(dynamic value)
{
try
{
if (value != null)
{
var valorCampos = "";
foreach (Newtonsoft.Json.Linq.JProperty item in value)
{
if (item.Name == "valorCampo")//property name
valorCampos = item.Value.ToString();
}
}
}
catch (Exception ex)
{
}
}
Some of the solutions were not working with a valuekind object that I obtained from a json string, maybe because I did not have a concrete type in my code that was similar to the object that I would obtain from the json string, so how I went about it was
JsonElement myObject = System.Text.Json.JsonSerializer.Deserialize<JsonElement>(jsonStringRepresentationOfMyObject);
/*In this case I know that there is a property with
the name Code, otherwise use TryGetProperty. This will
still return a JsonElement*/
JsonElement propertyCode = myObject.GetProperty("Code");
/*Now with the JsonElement that represents the property,
you can use several methods to retrieve the actual value,
in this case I know that the value in the property is a string,
so I use the GetString method on the object. If I knew the value
was a double, then I would use the GetDouble() method on the object*/
string code = propertyCode.GetString();
That worked for me
In .Net core 3.1 you can try like this
d?.value2 , d?.value3
Similar to the accepted answer, you can also try GetField instead of GetProperty.
d.GetType().GetField("value2").GetValue(d);
Depending on how the actual Type was implemented, this may work when GetProperty() doesn't and can even be faster.
In case you have a dynamic variable such as a DapperRow for example you can first build up an ExpandoObject, then cast the Expando into an IDictionary<string, object>. From then on, getting a value via the name of a property is possible.
Helper method ToExpandoObject:
public static ExpandoObject ToExpandoObject(object value)
{
IDictionary<string, object> dapperRowProperties = value as IDictionary<string, object>;
IDictionary<string, object> expando = new ExpandoObject();
if (dapperRowProperties == null)
{
return expando as ExpandoObject;
}
foreach (KeyValuePair<string, object> property in dapperRowProperties)
{
if (!expando.ContainsKey(property.Key))
{
expando.Add(property.Key, property.Value);
}
else
{
//prefix the colliding key with a random guid suffixed
expando.Add(property.Key + Guid.NewGuid().ToString("N"), property.Value);
}
}
return expando as ExpandoObject;
}
Sample usage, I have marked in bold the casting which gives us access in the example, I have marked the important bits with the ** letters:
using (var transactionScope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
{
foreach (var dynamicParametersForItem in dynamicParametersForItems)
{
var idsAfterInsertion = (await connection.QueryAsync<object>(sql, dynamicParametersForItem)).ToList();
if (idsAfterInsertion != null && idsAfterInsertion.Any())
{
**var idAfterInsertionDict = (IDictionary<string, object>) ToExpandoObject(idsAfterInsertion.First());**
string firstColumnKey = columnKeys.Select(c => c.Key).First();
**object idAfterInsertionValue = idAfterInsertionDict[firstColumnKey];**
addedIds.Add(idAfterInsertionValue); //we do not support compound keys, only items with one key column. Perhaps later versions will return multiple ids per inserted row for compound keys, this must be tested.
}
}
}
In my example, I look up a property value inside a dynamic object DapperRow and first convert the Dapper row into an ExpandoObject and cast it into a dictionary property bag as shown and mentioned in other answers here.
My sample code is the InsertMany method for Dapper extension I am working on, I wanted to grab hold of the multiple ids here after the batch insert.
Use dynamic with Newtonsoft.Json.JsonConvert.DeserializeObject:
// Get JSON string of object
var obj = new { value1 = "some", value2 = "random", value3 = "value" };
var jsonString = JsonConvert.SerializeObject(obj);
// Use dynamic with JsonConvert.DeserializeObject
dynamic d = JsonConvert.DeserializeObject(jsonString);
// output = "some"
Console.WriteLine(d["value1"]);
Sample:
https://dotnetfiddle.net/XGBLU1