I have a method
private static Dictionary<string, string> getRelationPropertyAttribute(Type type)
{
var dicRelation = new Dictionary<string, string>();
var properties = type.GetProperties();
foreach (var property in properties)
{
var attributes = property.GetCustomAttributes(inherit: false);
var customAttributes = attributes
.AsEnumerable()
.Where(a => a.GetType() == typeof(MongoDBFieldAttribute));
if (customAttributes.Count() <= 0)
continue;
for each (var attribute in custom attributes)
{
if (attribute is MongoDBFieldAttribute attr)
dicRelation[attr.Field] = property.Name;
}
}
return dicRelation;
}
In this typeof(MongoDBFieldAttribute) is getting me CustomAttributes list of all properties with
MOngoDBFieldAttribute type only and I have properties as :
[FieldIdentifier("SSI")]
[MongoDBField("Sender State ID")]
public string SenderStateID { get; set; }
[FieldIdentifier("SPH")]
[MongoDBField("Sender Phone")]
public string SenderPhone { get; set; }
How can I make the method generic so as to get Dictionary of MongoDBField or FieldIdentifier based on need?
There's already an (extension) method GetCustomAttributes<T>()
So you can write:
using System.Reflection;
var customAttributes = property.GetCustomAttributes<MongoDBFieldAttribute>();
foreach (var attribute in customAttributes)
{
dicRelation[attr.Field] = property.Name;
}
To make your method generic over the type of attribute, and return a dictionary where the keys are the attributes:
private static Dictionary<T, string> getRelationPropertyAttribute<T>(Type type) where T : Attribute
{
var dicRelation = new Dictionary<T, string>();
var properties = type.GetProperties();
foreach (var property in properties)
{
var customAttributes = property.GetCustomAttributes<T>();
foreach (var attribute in customAttributes)
{
dicRelation[attr] = property.Name;
}
}
return dicRelation;
}
Or you can use Linq to make it a bit terser:
private static Dictionary<T, string> getRelationPropertyAttribute<T>(Type type) where T : Attribute
{
var pairs = from property in type.GetProperties()
from attribute in property.GetCustomAttributes<T>()
select new KeyValuePair<T, string>(attribute, property.Name);
return new Dictionary<T, string>(pairs);
}
Are there any elegant quick way to map object to a dictionary and vice versa?
Example:
IDictionary<string,object> a = new Dictionary<string,object>();
a["Id"]=1;
a["Name"]="Ahmad";
// .....
becomes
SomeClass b = new SomeClass();
b.Id=1;
b.Name="Ahmad";
// ..........
Using some reflection and generics in two extension methods you can achieve that.
Right, others did mostly the same solution, but this uses less reflection which is more performance-wise and way more readable:
public static class ObjectExtensions
{
public static T ToObject<T>(this IDictionary<string, object> source)
where T : class, new()
{
var someObject = new T();
var someObjectType = someObject.GetType();
foreach (var item in source)
{
someObjectType
.GetProperty(item.Key)
.SetValue(someObject, item.Value, null);
}
return someObject;
}
public static IDictionary<string, object> AsDictionary(this object source, BindingFlags bindingAttr = BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance)
{
return source.GetType().GetProperties(bindingAttr).ToDictionary
(
propInfo => propInfo.Name,
propInfo => propInfo.GetValue(source, null)
);
}
}
class A
{
public string Prop1
{
get;
set;
}
public int Prop2
{
get;
set;
}
}
class Program
{
static void Main(string[] args)
{
Dictionary<string, object> dictionary = new Dictionary<string, object>();
dictionary.Add("Prop1", "hello world!");
dictionary.Add("Prop2", 3893);
A someObject = dictionary.ToObject<A>();
IDictionary<string, object> objectBackToDictionary = someObject.AsDictionary();
}
}
Convert the Dictionary to JSON string first with Newtonsoft.
var json = JsonConvert.SerializeObject(advancedSettingsDictionary, Newtonsoft.Json.Formatting.Indented);
Then deserialize the JSON string to your object
var myobject = JsonConvert.DeserializeObject<AOCAdvancedSettings>(json);
Seems reflection only help here.. I've done small example of converting object to dictionary and vise versa:
[TestMethod]
public void DictionaryTest()
{
var item = new SomeCLass { Id = "1", Name = "name1" };
IDictionary<string, object> dict = ObjectToDictionary<SomeCLass>(item);
var obj = ObjectFromDictionary<SomeCLass>(dict);
}
private T ObjectFromDictionary<T>(IDictionary<string, object> dict)
where T : class
{
Type type = typeof(T);
T result = (T)Activator.CreateInstance(type);
foreach (var item in dict)
{
type.GetProperty(item.Key).SetValue(result, item.Value, null);
}
return result;
}
private IDictionary<string, object> ObjectToDictionary<T>(T item)
where T: class
{
Type myObjectType = item.GetType();
IDictionary<string, object> dict = new Dictionary<string, object>();
var indexer = new object[0];
PropertyInfo[] properties = myObjectType.GetProperties();
foreach (var info in properties)
{
var value = info.GetValue(item, indexer);
dict.Add(info.Name, value);
}
return dict;
}
I'd highly recommend the Castle DictionaryAdapter, easily one of that project's best-kept secrets. You only need to define an interface with the properties you want, and in one line of code the adapter will generate an implementation, instantiate it, and synchronize its values with a dictionary you pass in. I use it to strongly-type my AppSettings in a web project:
var appSettings =
new DictionaryAdapterFactory().GetAdapter<IAppSettings>(ConfigurationManager.AppSettings);
Note that I did not need to create a class that implements IAppSettings - the adapter does that on the fly. Also, although in this case I'm only reading, in theory if I were setting property values on appSettings, the adapter would keep the underlying dictionary in sync with those changes.
I think you should use reflection. Something like this:
private T ConvertDictionaryTo<T>(IDictionary<string, object> dictionary) where T : new()
{
Type type = typeof (T);
T ret = new T();
foreach (var keyValue in dictionary)
{
type.GetProperty(keyValue.Key).SetValue(ret, keyValue.Value, null);
}
return ret;
}
It takes your dictionary and loops through it and sets the values. You should make it better but it's a start. You should call it like this:
SomeClass someClass = ConvertDictionaryTo<SomeClass>(a);
Reflection can take you from an object to a dictionary by iterating over the properties.
To go the other way, you'll have to use a dynamic ExpandoObject (which, in fact, already inherits from IDictionary, and so has done this for you) in C#, unless you can infer the type from the collection of entries in the dictionary somehow.
So, if you're in .NET 4.0 land, use an ExpandoObject, otherwise you've got a lot of work to do...
Building on MatÃas Fidemraizer's answer, here is a version that supports binding to object properties other than strings.
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace WebOpsApi.Shared.Helpers
{
public static class MappingExtension
{
public static T ToObject<T>(this IDictionary<string, object> source)
where T : class, new()
{
var someObject = new T();
var someObjectType = someObject.GetType();
foreach (var item in source)
{
var key = char.ToUpper(item.Key[0]) + item.Key.Substring(1);
var targetProperty = someObjectType.GetProperty(key);
//edited this line
if (targetProperty.PropertyType == item.Value.GetType())
{
targetProperty.SetValue(someObject, item.Value);
}
else
{
var parseMethod = targetProperty.PropertyType.GetMethod("TryParse",
BindingFlags.Public | BindingFlags.Static, null,
new[] {typeof (string), targetProperty.PropertyType.MakeByRefType()}, null);
if (parseMethod != null)
{
var parameters = new[] { item.Value, null };
var success = (bool)parseMethod.Invoke(null, parameters);
if (success)
{
targetProperty.SetValue(someObject, parameters[1]);
}
}
}
}
return someObject;
}
public static IDictionary<string, object> AsDictionary(this object source, BindingFlags bindingAttr = BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance)
{
return source.GetType().GetProperties(bindingAttr).ToDictionary
(
propInfo => propInfo.Name,
propInfo => propInfo.GetValue(source, null)
);
}
}
}
public class SimpleObjectDictionaryMapper<TObject>
{
public static TObject GetObject(IDictionary<string, object> d)
{
PropertyInfo[] props = typeof(TObject).GetProperties();
TObject res = Activator.CreateInstance<TObject>();
for (int i = 0; i < props.Length; i++)
{
if (props[i].CanWrite && d.ContainsKey(props[i].Name))
{
props[i].SetValue(res, d[props[i].Name], null);
}
}
return res;
}
public static IDictionary<string, object> GetDictionary(TObject o)
{
IDictionary<string, object> res = new Dictionary<string, object>();
PropertyInfo[] props = typeof(TObject).GetProperties();
for (int i = 0; i < props.Length; i++)
{
if (props[i].CanRead)
{
res.Add(props[i].Name, props[i].GetValue(o, null));
}
}
return res;
}
}
If you are using Asp.Net MVC, then take a look at:
public static RouteValueDictionary AnonymousObjectToHtmlAttributes(object htmlAttributes);
which is a static public method on the System.Web.Mvc.HtmlHelper class.
public Dictionary<string, object> ToDictionary<T>(string key, T value)
{
try
{
var payload = new Dictionary<string, object>
{
{ key, value }
};
} catch (Exception e)
{
return null;
}
}
public T FromDictionary<T>(Dictionary<string, object> payload, string key)
{
try
{
JObject jObject = (JObject) payload[key];
T t = jObject.ToObject<T>();
return (t);
}
catch(Exception e) {
return default(T);
}
}
I have a little test class like so :
public class Command
{
public dynamic MyData { get; set; }
}
As the dynamic MyData I want to use ExpandoObject, so I can do:
Command cmd = new Command();
cmd.MyData = new ExpandoObject();
cmd.MyData.SomeStuff = 4;
cmd.MyData.SomeOtherStuff = "hi";
I am trying to serialize to/deserialize from json. To do this I am using JavaScriptSerializer.
I want an example object above to serialize to:
{
MyData : {
SomeStuff : 4,
SomeOtherStuff : "hi"
}
}
To do this I need a JavaScriptConverter (taken from this website):
public class ExpandoJsonConverter : JavaScriptConverter
{
public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
{
return dictionary.ToExpando();
}
public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
{
var result = new Dictionary<string, object>();
var dictionary = obj as IDictionary<string, object>;
foreach (var item in dictionary)
result.Add(item.Key, item.Value);
return result;
}
public override IEnumerable<Type> SupportedTypes
{
get
{
return new ReadOnlyCollection<Type>(new Type[] { typeof(ExpandoObject) });
}
}
}
public static class IDictionaryExtensions {
/// <summary>
/// Extension method that turns a dictionary of string and object to an ExpandoObject
/// Snagged from http://theburningmonk.com/2011/05/idictionarystring-object-to-expandoobject-extension-method/
/// </summary>
public static ExpandoObject ToExpando(this IDictionary<string, object> dictionary) {
var expando = new ExpandoObject();
var expandoDic = (IDictionary<string, object>)expando;
// go through the items in the dictionary and copy over the key value pairs)
foreach (var kvp in dictionary) {
// if the value can also be turned into an ExpandoObject, then do it!
if (kvp.Value is IDictionary<string, object>) {
var expandoValue = ((IDictionary<string, object>)kvp.Value).ToExpando();
expandoDic.Add(kvp.Key, expandoValue);
}
else if (kvp.Value is ICollection) {
// iterate through the collection and convert any strin-object dictionaries
// along the way into expando objects
var itemList = new List<object>();
foreach (var item in (ICollection)kvp.Value) {
if (item is IDictionary<string, object>) {
var expandoItem = ((IDictionary<string, object>)item).ToExpando();
itemList.Add(expandoItem);
}
else {
itemList.Add(item);
}
}
expandoDic.Add(kvp.Key, itemList);
}
else {
expandoDic.Add(kvp);
}
}
return expando;
}
}
Now this works neat for serializing, but there is a following problem with deserializing:
since MyData is a dynamic object, and the ExpandoJsonConverter expects ExpandoObject, the data deserialized to MyData is of type IDictionary<string, object>.
if I change dynamic MyData to be ExpandoObject MyData, I won't be able to say cmd.MyData.SomeStuff = 4;, the compiler will tell me that "ExpandoObject does not have property named SomeStuff".
finally, I could add dynamic to the list of supported types of ExpandoJsonConverter, byt wait, you cant do typeof(dynamic).
Is anyone aware of a neat workaround? I would really like this functionality, but I can't use 3rd party serialization libraries like Newtonsoft. Thanks.
Deserialize to ExpandoObject but declare the variable dynamic, i.e. what you need is dynamic d = js.Deserialize<ExpandoObject>(json):
string json = #"{
MyData : {
SomeStuff : 4,
SomeOtherStuff : ""hi""
}
}";
var js = new JavaScriptSerializer();
js.RegisterConverters(new[] { new ExpandoJsonConverter() });
dynamic d = js.Deserialize<ExpandoObject>(json);
Console.WriteLine(d.MyData.SomeOtherStuff);
Output:
hi
If you need a Command object, just construct one manually and inject the dynamic object returned from the serializer:
var cmd = new Command { MyData = d };
Console.WriteLine(cmd.MyData.SomeStuff);
I have a dictionary collection of more than 100 fields and values. Is there a way to populate a gigantic class with a 100 fields using this collection?
The key in this dictionary corresponds to the property name of my class and the value would be the Value of the Property for the class.
Dictionary<string, object> myDictionary = new Dictionary<string, object>();
myDictionary.Add("MyProperty1", "Hello World");
myDictionary.Add("MyProperty2", DateTime.Now);
myDictionary.Add("MyProperty3", true);
Populates the properties of the following class.
public class MyClass
{
public string MyProperty1 {get;set;}
public DateTime MyProperty2 {get;set;}
public bool MyProperty3 {get;set;}
}
You can use GetProperties to get a list of properties for a given type and use SetValue to set a specific value for a given property:
MyClass myObj = new MyClass();
...
foreach (var pi in typeof(MyClass).GetProperties())
{
object value;
if (myDictionary.TryGetValue(pi.Name, out value)
{
pi.SetValue(myObj, value);
}
}
Use
MyClass yourinstance...
foreach (var KVP in myDictionary)
{
yourinstance.GetType().GetProperty ( KVP.Key ).GetSetMethod().Invoke ( yourinstance, new object[] { KVP.Value } );
}
I have a static class which only contains string properties. I want to convert that class into a name-value pair dictionary with key=PropName, value=PropValue.
Below is the code I have written:
void Main()
{
Dictionary<string, string> items = new Dictionary<string, string>();
var type = typeof(Colors);
var properties = type.GetProperties(BindingFlags.Static);
/*Log properties found*/
/*Iam getting zero*/
Console.WriteLine("properties found: " +properties.Count());
foreach (var item in properties)
{
string name = item.Name;
string colorCode = item.GetValue(null, null).ToString();
items.Add(name, colorCode);
}
/*Log items created*/
Console.WriteLine("Items in dictionary: "+items.Count());
}
public static class Colors
{
public static string Gray1 = "#eeeeee";
public static string Blue = "#0000ff";
}
Output
properties found: 0
Items in dictionary: 0
It's not reading any properties - can anybody tell me what's wrong with my code?
The members in your Colors class are no properties but fields.
Use GetFields in the place of the GetProperties method.
You might end up with something like (also not the change in the call to GetValue):
var properties = type.GetFields(BindingFlags.Static);
/*Log properties found*/
/*Iam getting zero*/
Console.WriteLine("properties found: " +properties.Count());
foreach (var item in properties)
{
string name = item.Name;
string colorCode = item.GetValue(null).ToString();
items.Add(name, colorCode);
}
You can use linq to condense the conversion to a couple of lines:
var type = typeof(Colors);
var fields = type.GetFields().ToDictionary(f => f.Name, f => f.GetValue(f).ToString());
Use this:
var properties = type.GetFields(BindingFlags.Static|BindingFlags.Public);