Словарь с объектом как значение

Я здесь схожу. Вероятно, потому, что я пропустил какое-то правило, но если так, то, пожалуйста, скажите мне.

Я пытаюсь создать Dictionary с строкой для ключа и анонимным объектом в качестве значения. Или, на самом деле, я не просто пытаюсь, я это делаю. Но когда я хочу изменить конкретный параметр в объекте, он идет не так.

Я объявляю словарь следующим образом:

var areas = new Dictionary<string, object>
{
  {"Key1", new {name = "Name1", today = 0, all = 0}},
  {"Key2", new {name = "Name2", today = 0, all = 0}},
    ...
}

И тогда я предполагаю, что смогу это сделать:

foreach (var area in areas.Keys.ToArray())
{
    var areaname = areas[area].name;
}

но Visual Studio не соглашается и отказывается компилировать. Если я пишу это, все работает так, как я думаю, но это на самом деле не помогает мне, это просто делает меня более расстроенным.

var areaname = new 
            {
                 name = "Nametest", today = 0, all = 0
            };
var testname = areaname.name;

Что я делаю не так? Почему это не работает для меня? Это просто невозможно сделать?

Спасибо за все ваши ответы, они, конечно, немного разобрались! Я думаю, что, возможно, я запутал объект типа с идеей объектов, то есть классов, в С# из-за разочарования. Я переосмыслил весь дизайн и, возможно, сделаю что-то совершенно другое, вместо того, чтобы использовать злые или грязные решения. Хотя интересно, я не думаю, что мои отношения с С# еще не развились!

Ответ 1

Это не будет работать, потому что вы объявили словарь как Dictionary<string, object>.

Вместо этого вы можете попробовать Dictionary<string, dynamic>.

Ответ 2

Это не компилируется, потому что значения в вашем словаре имеют тип object а object не содержит name свойства.

Если вы используете.NET 4, вы можете изменить тип с object на dynamic.

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

Ответ 3

Это не будет работать, потому что вы объявили словарь как Dictionary<string, object>.

С# создает новый тип в фоновом режиме для вас (к которому вы не можете получить доступ), который имеет эти свойства (при этом известный как анонимный тип). Единственный раз, когда вы можете использовать его напрямую, - это когда он все еще является типом var - как только вы добавляете его в этот словарь, он прикладывается к object и, следовательно, вы больше не можете обращаться к свойствам.

Опция 1

Вместо этого вы можете попробовать Dictionary<string, dynamic>. Dynamic сможет получить доступ к этим свойствам, но это поддерживается только в С#/.NET 4.0

Вариант 2

Вы можете вернуть тип с помощью техники, известной как демонстрация (например, на примере). Это не задокументированная функция, расточительна и немного взломана. Это ужасный злой трюк - особенно потому, что он не будет работать через собрания.

public static T Demonstrate<T>(this T demonstration, object value)
{
    return (T)value;
}

Затем вы можете получить доступ к исходным свойствам следующим образом:

var area = new { name = "", today = 0, all = 0 }.Demonstrate(areas[name]);
var areaName = value.name;

Вариант 3 Это, честно говоря, лучший способ

Напишите класс. Если вам нравится тот факт, что компилятор С# делает все Equals, GetHashCode и ToString для вас, вы можете просто использовать что-то вроде ILSpy для захвата исходного кода. Таким образом:

class AreaInfo
{
    public string Name { get; set; }
    public int Total { get; set; }
    public int All { get; set; }

    public override bool Equals(object obj)
    {
        var ai = obj as AreaInfo;
        if (object.ReferenceEquals(ai, null))
            return false;
        return Name == ai.Name && Total == ai.Total && All == ai.All;
    }

    public override int GetHashCode()
    {
        var hc = 0;
        if (Name != null)
            hc = Name.GetHashCode();
        hc = unchecked((hc * 7) ^ Total);
        hc = unchecked((hc * 21) ^ All);
        return hc;
    }

    public override string ToString()
    {
        return string.Format("{{ Name = {0}, Total = {1}, All = {2} }}", Name, Total, All);
    }
}

Исправьте словарь:

var areas = new Dictionary<string, AreaInfo>       
{       
  {"Key1", new AreaInfo() {Name = "Name1", Today = 0, All = 0}},       
  {"Key2", new AreaInfo() {Name = "Name2", Today = 0, All = 0}},       
    ...       
};

И теперь все будет работать так, как вы ожидаете.

Ответ 4

Чтобы получить свой словарь для правильного анонимного типа для его значения, сделайте следующее:

var areas=new[] {
  new {Key="Key1", Value=new {name="Name1", today=0, all=0}},
  new {Key="Key2", Value=new {name="Name2", today=0, all=0}},
}.ToDictionary(kv => kv.Key, kv => kv.Value);

Тогда ваш код будет работать так, как ожидалось:

foreach(var area in areas.Keys.ToArray()) {
  var areaname=areas[area].name;
}

Ответ 5

Детали анонимных типов не переносятся за рамки сборки, в которой они созданы, и не легко видимы за пределами метода, в котором они создаются. Вместо этого вы должны использовать вместо него явный тип или dynamic если вы хотите использовать динамический подход,

† Здесь есть злой трюк, который я намеренно не упоминаю, потому что он злой.