Подтвердить что ты не робот

Сопоставление объекта со словарем и наоборот

Есть ли элегантный способ быстрого сопоставления объекта со словарем и наоборот?

Пример:

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

становится

SomeClass b = new SomeClass();
b.Id=1;
b.Name="Ahmad";
// ..........
4b9b3361

Ответ 1

Используя некоторые отражения и дженерики в двух расширениях методов, вы можете достичь этого.

Правильно, другие делали в основном одно и то же решение, но это использует меньшее отражение, которое более эффективно и удобнее для чтения:

public static class ObjectExtensions
{
    public static T ToObject<T>(this IDictionary<string, object> source)
        where T : class, new()
    {
            T someObject = new T();
            Type someObjectType = someObject.GetType();

            foreach (KeyValuePair<string, object> 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();
    }
}

Ответ 2

Кажется, здесь отражается только помощь. Я сделал небольшой пример преобразования объекта в словарь и наоборот:

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

Ответ 3

Я очень рекомендую Castle DictionaryAdapter, легко один из самых лучших секретов этого проекта. Вам нужно только определить интерфейс с требуемыми свойствами, а в одной строке кода адаптер будет генерировать реализацию, создать экземпляр и синхронизировать свои значения со словарем, в который вы проходите. Я использую его для сильного ввода моего AppSettings в веб-проект:

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

Обратите внимание, что мне не нужно создавать класс, который реализует IAppSettings - адаптер делает это на лету. Кроме того, хотя в этом случае я только читаю, теоретически, если бы я задавал значения свойств в appSettings, адаптер сохранил бы базовый словарь в синхронизации с этими изменениями. Вот хороший учебник:

http://blog.andreloker.de/post/2008/06/10/Castle-DictionaryAdapter.aspx

Ответ 4

Отражение может переносить вас из объекта в словарь, итерации по свойствам.

Чтобы перейти в другую сторону, вам придется использовать динамический ExpandoObject (который, по сути, уже наследуется от IDictionary, и так сделал это для вас) в С#, если вы не можете вывести тип из коллекции записей в словаре как-то.

Итак, если вы находитесь в среде .NET 4.0, используйте ExpandoObject, иначе у вас будет много работы...

Ответ 5

Я думаю, вы должны использовать отражение. Что-то вроде этого:

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

Он принимает ваш словарь и проходит через него и устанавливает значения. Вы должны сделать это лучше, но это начало. Вы должны называть это следующим образом:

SomeClass someClass = ConvertDictionaryTo<SomeClass>(a);

Ответ 6

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

Ответ 7

Если вы используете Asp.Net MVC, посмотрите на:

public static RouteValueDictionary AnonymousObjectToHtmlAttributes(object htmlAttributes);

который является статическим общедоступным методом в классе System.Web.Mvc.HtmlHelper.

Ответ 8

На основе ответа Matías Fidemraizer, это версия, которая поддерживает привязку к объектным свойствам, отличным от строк.

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

Ответ 9

Преобразуйте словарь в строку JSON сначала с помощью Newtonsoft.

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

Затем десериализуем строку JSON для вашего объекта

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