开发者

Dictionary with object as value

I'm going nuts here. It's probably because I've missed some rule, but if so, then please tell me.

I'm trying to create a Dictionary with a string for key and an anonymous object as value. Or, actually I'm not just trying, I'm doing it. But when I want to alter a specific parameter in the object, it goes wrong.

I declare the dictionary like this:

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

And then I'm assuming I can do this:

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

but Visual Studio does not agree, and refuses to compile. If I write this, though, everything works as I would think - but that doesn't really help me out, it's just making me more frustrated.

var areaname = new 
            {
                 name = "Nametes开发者_如何学编程t", today = 0, all = 0
            };
var testname = areaname.name;

What am I doing wrong? Why isn't it working for me? Is it simply impossible to do so?

Thanks for all your answers, they surely cleared things up a bit! I think I might have been confusing the type object with the idea of objects, that is classes, in C# out of frustration. I'll rethink the whole design business and probably do something completely different instead of using evil or dirty solutions. Though interesting, I don't think my relationship with C# has evolved that far yet!


This will not work because you have declared the dictionary as Dictionary<string, object>.

You could instead try Dictionary<string, dynamic>.


This will not work because you have declared the dictionary as Dictionary<string, object>.

C# creates a new type in the background for you (which you can't access) that has these properties (herewith known as an anonymous type). The only time you can use it directly is when it is still var type - as soon as you add it to that dictionary it is cast to object and thus you can't access the properties any more.

Option 1

You could instead try Dictionary<string, dynamic>. Dynamic will be able to access these properties - but this is only supported in C#/.Net 4.0

Option 2

You can get the type back using a technique known as demonstration (cast by example). This isn't a documented feature, is wasteful and is somewhat a hack. This is a horrible evil trick - especially because it won't work across assemblies.

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

You can then access the original properties like so:

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

Option 3 This is honestly the best way

Write a class. If you like the fact that the C# compiler does all of the Equals, GetHashCode and ToString work for you, you can just use something like ILSpy to grab the original code. Thus:

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

Correct your dictionary:

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

And now things will work the way you expect them to.


This doesn't compile, because the values in your dictionary are of type object and object doesn't contain a property name.

If you are using .NET 4 you could change the type from object to dynamic.

Having said this, I strongly disagree with this design decision. You really should create a class for this.


To get your Dictionary to have the proper anonymous type for its value, do this:

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

Then your code will work as expected:

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


The details of anonymous types aren't portable beyond the assembly they are created in, and aren't readily† visible beyond the method they are created in. You should use an onymous type instead, or dynamic if you want to adopt a dynamic approach.

† there is an evil trick here which I'm deliberately not mentioning, because it's evil.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜