webentwicklung-frage-antwort-db.com.de

Zuordnen eines Objekts zum Wörterbuch und umgekehrt

Gibt es eine elegante schnelle Möglichkeit, ein Objekt einem Wörterbuch zuzuordnen und umgekehrt?

Beispiel:

IDictionary<string,object> a = new Dictionary<string,object>();
a["Id"]=1;
a["Name"]="Ahmad";
// .....

wird

SomeClass b = new SomeClass();
b.Id=1;
b.Name="Ahmad";
// ..........
76
Sawan
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;
    }
}
2
Sawan

Mit etwas Reflektion und Generika in zwei Erweiterungsmethoden können Sie dies erreichen.

Richtig, andere haben größtenteils dieselbe Lösung verwendet, aber dies erfordert weniger Reflexion, was in Bezug auf die Leistung und die Lesbarkeit besser ist:

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();
    }
}
157

Konvertieren Sie das Dictionary zuerst mit Newtonsoft in einen JSON-String.

var json = JsonConvert.SerializeObject(advancedSettingsDictionary, Newtonsoft.Json.Formatting.Indented);

Deserialisieren Sie dann die JSON-Zeichenfolge für Ihr Objekt

var myobject = JsonConvert.DeserializeObject<AOCAdvancedSettings>(json);
16
learnerplates

Scheint hier nur zu helfen .. Ich habe ein kleines Beispiel für das Konvertieren von Objekten in ein Wörterbuch gemacht und umgekehrt:

[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;
}
11
Andrew Orsich

Ich würde das Castle DictionaryAdapter wärmstens empfehlen, eines der am besten gehüteten Geheimnisse dieses Projekts. Sie müssen nur eine Schnittstelle mit den gewünschten Eigenschaften definieren. In einer Codezeile generiert der Adapter eine Implementierung, instanziiert sie und synchronisiert ihre Werte mit einem von Ihnen übergebenen Wörterbuch ein Webprojekt:

var appSettings =
  new DictionaryAdapterFactory().GetAdapter<IAppSettings>(ConfigurationManager.AppSettings);

Beachten Sie, dass ich keine Klasse erstellen musste, die IAppSettings implementiert - der Adapter erledigt dies im laufenden Betrieb. Obwohl ich in diesem Fall nur lese, würde der Adapter theoretisch das zugrunde liegende Wörterbuch mit diesen Änderungen synchron halten, wenn ich Eigenschaftswerte für appSettings festlegte.

10
Todd Menier

Reflexion kann Sie von einem Objekt zu einem Wörterbuch führen, indem Sie die Eigenschaften durchlaufen.

Um in die andere Richtung zu gehen, müssen Sie ein dynamisches ExpandoObject (das tatsächlich bereits von IDictionary erbt und dies auch für Sie getan hat) in C # verwenden, es sei denn, Sie können auf den Typ schließen irgendwie aus der Sammlung von Einträgen im Wörterbuch.

Wenn Sie sich in .NET 4.0 befinden, verwenden Sie ein ExpandoObject. Andernfalls haben Sie viel zu tun ...

5
Massif

Ich denke, Sie sollten Reflexion verwenden. Etwas wie das:

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;
}

Es nimmt Ihr Wörterbuch und durchläuft es und legt die Werte fest. Sie sollten es besser machen, aber es ist ein Anfang. Sie sollten es so nennen:

SomeClass someClass = ConvertDictionaryTo<SomeClass>(a);
4
TurBas

Aufbauend auf der Antwort von Matías Fidemraizer ist hier eine Version, die das Binden an andere Objekteigenschaften als Strings unterstützt.

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);


                if (targetProperty.PropertyType == typeof (string))
                {
                    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)
            );
        }
    }
}
2
Daniel Lewis
    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);
        }
    }
0
Williams Abiola

Wenn Sie Asp.Net MVC verwenden, schauen Sie sich Folgendes an:

public static RouteValueDictionary AnonymousObjectToHtmlAttributes(object htmlAttributes);

hierbei handelt es sich um eine statische öffentliche Methode für die System.Web.Mvc.HtmlHelper-Klasse.

0
magritte