0

Having a class defined:

[DataContract]
public class Command
{
        [DataMember(Name = "cmdName")]
        public string CommandName { get; set; }

        [DataMember(Name = "cmdTransactionId")]
        public string CommandTransactionId { get; set; }
}

I would like to create an instance of that class from a dictionary:

Dictionary<string, object> propertyBag = new Dictionary<string, object>();
propertyBag["cmdName"] = "cmd1";
propertyBag["cmdTransactionId"] = "1";
Command command = deserializer.Create<Command>(propertyBag);

DataContractSerializer is not working for me nor is the JavaScriptSerializer.ConvertToType as each of them is missing a piece that stop s me from creating objects in one go.

algorytmus
  • 953
  • 2
  • 9
  • 28
  • 3
    Could you use `var command = new Command { CommandName = "cmd1", CommandTransactionId = "1" };`? – Sebastian Schumann Jan 11 '16 at 12:17
  • This is significantly simplified (just an example) I have 30 DataContract classes and with 300 properties like this. Instead of DataMember I could use JsonProperty for example. – algorytmus Jan 11 '16 at 12:56
  • What I would probably try first is take your dictionary of properties. Convert those "objects" to a JSON string. Then convert that JSON string to the actual object class. With that pattern, you're basically recreating the client-to-server behavior of JSON over an API or from form data. – krillgar Jan 11 '16 at 13:01
  • What type of object is `deserializer`? A [`DataContractSerializer`](https://msdn.microsoft.com/en-us/library/system.runtime.serialization.datacontractserializer(v=vs.110).aspx) does not contain a method `Create`. – Sebastian Schumann Jan 11 '16 at 13:07
  • deserializer is just a mock which I am looking for to replace. – algorytmus Jan 11 '16 at 13:08

2 Answers2

2

JavaScriptSerializer will work here with some changes:

var propertyBag = new Dictionary<string, object>();
propertyBag["CommandName"] = "cmd1";
propertyBag["CommandTransactionId"] = "1";

var serializer = new JavaScriptSerializer();
var res = serializer.Serialize(propertyBag);

var command = serializer.Deserialize<Command>(res);

I used Deserialize method instead of ConvertToType one. The second difference is more significant. A dictionary used by me contains keys which are the same as names of properties in Command class. If you don't like it you should try to write a custom JavaScriptConverter. See this question.

Community
  • 1
  • 1
Michał Komorowski
  • 6,198
  • 1
  • 20
  • 24
  • Did you try to use solutions proposed in the question pointed by me? It seems to me that they do not require renaming of keys or properties. – Michał Komorowski Jan 11 '16 at 13:52
  • I cannot change keys in the propertyBag dictionary (they are produced by other components of which I do not have control over) hence this will not work for me ("cmdName" != "CommandName"). I cannot rename my properties neither. – algorytmus Jan 11 '16 at 13:54
0

Maybe you can try this code for deserializer.Create<Command>(propertyBag):

public T Create<T>(IDictionary<string, object> propertyBag)
{
    var result = (T)FormatterServices.GetUninitializedObject(typeof(T));

    foreach (var item in from member in typeof(T).GetMembers()
                         let dataMemberAttr = member.GetCustomAttributes(typeof(DataMemberAttribute), true).Cast<DataMemberAttribute>().SingleOrDefault()
                         where dataMemberAttr != null && propertyBag.ContainsKey(dataMemberAttr.Name)
                         select new { Member = member, Value = propertyBag[dataMemberAttr.Name] })
    {
        var property = item.Member as PropertyInfo;
        if (property != null)
        {
            property.SetValue(result, item.Value, null);
            continue;
        }

        var field = item.Member as FieldInfo;
        if (field != null)
        {
            field.SetValue(result, item.Value);
            continue;
        }
    }

    return result;
}

This code is not tested - just typed here.

Sebastian Schumann
  • 3,204
  • 19
  • 37