Словарь с объектом в качестве значения - PullRequest
13 голосов
/ 06 сентября 2011

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

Я пытаюсь создать 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;

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

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

Ответы [ 5 ]

24 голосов
/ 06 сентября 2011

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

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

10 голосов
/ 06 сентября 2011

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

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

Вариант 1

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

Option 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 Это, честно говоря, лучший способ

Написать класс.Если вам нравится тот факт, что компилятор C # выполняет все функции 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}},       
    ...       
};

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

9 голосов
/ 06 сентября 2011

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

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

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

7 голосов
/ 06 сентября 2011

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

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;
}
1 голос
/ 06 сентября 2011

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...