Как создать класс из словаря в С#?

Я написал метод, который создает словарь. Мне нужно преобразовать этот словарь в класс.

Пример словаря

 Dictionary<string, dynamic> myDictionary = new Dictionary<string, dynamic> {
            { "ID1", 12 },
            { "ID2", "Text2"},
            { "ID3", "Text3" }
        };

и это образец класса, который необходимо создать:

public class Foo
    {
        public int ID1 { get; set; }
        public string ID2 { get; set; }
        public string ID3 { get; set; }
    }

person Ehsan Aliverdi    schedule 16.06.2019    source источник
comment
Похоже, вы уже создали класс. Какой у Вас вопрос? Вы не знаете, как извлекать значения из словаря, не знаете, как присваивать значения свойствам объекта или что?   -  person John Wu    schedule 17.06.2019
comment
@JohnWu Это всего лишь образцы. Словарь Sample создается во время выполнения (я понятия не имею о ключах/типе). Во время выполнения мне нужно создать класс из этого словаря.   -  person Ehsan Aliverdi    schedule 17.06.2019
comment
Когда вы говорите создать класс, вы имеете в виду создание экземпляра этого класса и заполнение его свойств или фактически создание типа с этими свойствами? Если второе, то как бы вы использовали его в своей программе после его создания?   -  person Llama    schedule 17.06.2019
comment
Это действительно необычное требование, чтобы программа могла создавать класс во время выполнения. Странно, на самом деле. Смысл классов (и типов в целом) в том, что они используются во время компиляции, чтобы обеспечить правильную структуру вашей программы. Возможно, у вас возникла проблема xy.   -  person John Wu    schedule 17.06.2019
comment
Нет, я на самом деле имею в виду сам класс. Можно ли преобразовать ключ словаря в член класса во время выполнения?   -  person Ehsan Aliverdi    schedule 17.06.2019


Ответы (2)


Ваши требования не сформулированы четко, но я предполагаю, что вы ищете динамический тип со свойствами, имена которых сопоставляются с ключами словаря.

В этом случае вы можете использовать простую оболочку словаря, подобную этой:

class DynamicDictionaryWrapper : DynamicObject
{
    protected readonly Dictionary<string,object> _source;

    public DynamicDictionaryWrapper(Dictionary<string,object> source)
    {
        _source = source;
    }

    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        result = null;
        return (_source.TryGetValue(binder.Name, out result));
    }
}

Что вы можете использовать таким образом:

public static void Main()
{
    var myDictionary = new Dictionary<string, dynamic> {
        { "ID1", 12 },
        { "ID2", "Text2"},
        { "ID3", "Text3" }
    };  
    dynamic myObject = new DynamicDictionaryWrapper(myDictionary);

    Console.WriteLine(myObject.ID1);
    Console.WriteLine(myObject.ID2);
    Console.WriteLine(myObject.ID3);
}

Вывод:

12
Text2
Text3

Ссылка на рабочий пример в DotNetFiddle

person John Wu    schedule 17.06.2019

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

1. Требуют времени на разработку; незначительное время выполнения. Просто создайте функцию, которая сопоставляет заданный словарь с экземпляром вашего класса. Пример:

Foo MapDictionaryToFoo(IReadOnlyDictionary<string, dynamic> d)
{
    return new Foo
    {
        ID1 = d[nameof(Foo.ID1)],
        ID2 = d[nameof(Foo.ID2)],
        ID3 = d[nameof(Foo.ID3)]
    };
}

Пример вызова:

Foo myFoo = MapDictionaryToFoo(myDictionary);

2. Требовать время выполнения; незначительное время разработки. Создайте функцию, которая сопоставляет данный словарь с произвольным классом, обычно используя Reflection. В приведенном ниже примере предполагается, что ваш класс имеет конструктор по умолчанию, поэтому он также действует как фабрика. Если это не так, существующий экземпляр можно передать в дополнительном параметре:

T CreateFromDictionary<T>(IReadOnlyDictionary<string, dynamic> d) where T : new()
{
    T obj = new T();

    foreach (var propertyInfo in typeof(T).GetProperties())
    {
        propertyInfo.SetValue(obj, d[propertyInfo.Name]);
    }

    return obj;
}

Пример вызова:

Foo myFoo = CreateFromDictionary<Foo>(myDictionary);

Если мне нужно выбрать один, я бы выбрал первый подход, поскольку я избегаю любого отражения, которое занимает много времени во время выполнения.

person Jämes    schedule 17.06.2019