4

I'm trying to do the following.

private static Dictionary<int, object> MAPS = new Dictionary<int, object>
{
  {1, new {1, 2, 3}}
};

It doesn't work as I'd expect based on MSDN, so I'm pretty certain that the issue is that I'm using anonymous objects. Supposed that I don't want to create a new type for my thingies and still want to keep all the mappings in the same dictionary, what should I do?

I've seen this answer but it's a bit dated now so I'm hoping there's something new for that in the framework.

Community
  • 1
  • 1
Konrad Viltersten
  • 36,151
  • 76
  • 250
  • 438
  • 1
    Instead of saying _"doesn't work as I'd expect"_ it would be helpful if you'd show the actual compiler error, which is _"Invalid anonymous type member declarator. Anonymous type members must be declared with a member assignment, simple name or member access"_. – CodeCaster Oct 17 '14 at 11:29
  • @CodeCaster Point taken. I assumed that it was something basic and that I just got a brain poof. But you're correct, no argument. :) – Konrad Viltersten Oct 17 '14 at 11:31

4 Answers4

6

Try this if you want an array of ints as the value.

private static Dictionary<int, object> MAPS = new Dictionary<int, object>
{
  {1, new[] {1, 2, 3}}
};

Or this if you want an anonymous class

private static Dictionary<int, object> MAPS = new Dictionary<int, object>
{
  {1, new { a = 1, b = 2, c = 3}}
};

Or better yet don't use object. Use int[] or List<int> for a collection of int or declare a class or struct if you need specific values. Maybe even use Tuple<int,int,int> if you just need 3 ints for each value. But, in general you should try to avoid the need to cast to and from object.

juharr
  • 31,741
  • 4
  • 58
  • 93
  • Oh, I tried setting brackets on **both** the new operator **and** the object type in the angles. And I tried colon instead of equality sign. Stupid JSON damaged me... :) +1 – Konrad Viltersten Oct 17 '14 at 11:24
  • Is it possible to type the *a*. *b* and *c* without declaring a class for them? – Konrad Viltersten Oct 17 '14 at 11:30
  • They will implicitly take the type of what you set them to, so if needed you can cast the value. But the main problem you'll have with an anonymous class here is that you can not cast to it when you pull the value from the dictionary. You might want to look into using `dynamic` instead of `object`. – juharr Oct 17 '14 at 11:34
3

Further to the answers from @TimSchmelter and @juharr, if you want to be able to reference the properties via their names but you don't want to create a class you could use dynamic (although obviously you won't get any intellisense so it's use is limited):

Dictionary<int, object> MAPS = new Dictionary<int, object>
{
    {1, new { a = 1, b = 2, c = 3} as dynamic}
};

Console.WriteLine(((dynamic)MAPS[1]).b); //prints 2

Or if you made the Dictionary a Dictionary<int, dynamic> you could forgo the cast which makes life a little easier:

Dictionary<int, dynamic> MAPS = new Dictionary<int, object>
{
    {1, new { a = 1, b = 2, c = 3}}
};

Console.WriteLine(MAPS[1].b); //prints 2

The only benefit to using object or dynamic is that you can have a collection with different types stored in it. If you are only storing ints then you're best off using a List<int> or int[].

petelids
  • 12,305
  • 3
  • 47
  • 57
2

An anonymous type is just a type with properties, your anonymus type has no properties:

private static Dictionary<int, object> MAPS = new Dictionary<int, object>
{
    {1, new { Prop1 = 1, Prop2 = 2, Prop3 = 3}}
};

But how do you want to cast from object to that anoymous type?

Edit: Good question there, though. Do I have to cast MAPS[1][0] or is there a way to force a type implicitly there?

You cannot cast an object to an anonymous type without a hack like this extension method:

public static T CastByPrototype<T>(this object obj, T prototype)
{
    return (T)obj;
}

It uses a prototype anonymous type like:

var prototype = new { Prop1 = 0, Prop2 = 0, Prop3 = 0 };

Now this works:

var value = MAPS[1].CastByPrototype(prototype);  // you can use value.Prop1

It fails with an InvalidCastException if the prototype has not identical properties(in the same order).

Tim Schmelter
  • 450,073
  • 74
  • 686
  • 939
  • Good question there, though. Do I have to cast *MAPS[1][0]* or is there a way to force a type implicitly there? – Konrad Viltersten Oct 17 '14 at 11:29
  • @KonradViltersten if you want to be able to get to a value with `MAPS[1][0]` then why not make it a `Dictionary` or `Dictionary>` instead? – juharr Oct 17 '14 at 11:37
1

The syntax new {1, 2, 3} is not a collection initializer nor an anonymous object initializer. What type of object do you want to create?

Use something like new { elements = new[] { 1, 2, 3 } } to give the anonymous object an elements property containing the integers.

Or you can name the individual properties: new { foo = 1, bar = 2, baz = 3 }.

CodeCaster
  • 147,647
  • 23
  • 218
  • 272