views:

278

answers:

5
+2  Q: 

Anonymous Types

I have a Dictionary(TKey, TValue) like

Dictionary<int, ArrayList> Deduction_Employees = 
    new Dictionary<int, ArrayList>();

and later I add to that array list an anonymous type like this

var day_and_type = new {
    TheDay = myDay,
    EntranceOrExit = isEntranceDelay
};

Deduction_Employees[Employee_ID].Add(day_and_type);

Now how can I unbox that var and access those properties ??

+1  A: 

No you can't. You can only access the properties by using reflection. The compiler has no way of knowing what the type was, and since it's an anonymous type, you can't cast it either.

Philippe Leybaert
+1  A: 

If you are using .NET 1.x - 3.x, you must use reflection.

If you use .NET 4.0, you could use a dynamic type and call the expected properties.

In neither case do you need to unbox; that's for value types. Anonymous types are always reference types.

Randolpho
+3  A: 

An anonymous type has method scope. To pass an anonymous type, or a collection that contains anonymous types, outside a method boundary, you must first cast the type to object. However, this defeats the strong typing of the anonymous type. If you must store your query results or pass them outside the method boundary, consider using an ordinary named struct or class instead of an anonymous type.

Source: http://msdn.microsoft.com/en-us/library/bb397696.aspx

Kobi
+3  A: 

There are several ways.

Since the comments seems to indicate that I suggest you do this, let me make it clear: You should be creating a named type for your object since you intend to pass it around.

First, you can use Reflection, which another answer here has already pointed out.

Another way, which tricks .NET into giving you the right type is known as "cast by example", and it goes something like this: You need to pass your object through a generic method call, which will return the object as the right type, by inferring the right type to return.

For instance, try this:

private static T CastByExample<T>(T example, object value)
{
    return (T)value;
}

and to use it:

var x = CastByExample(new { TheDay = ??, EntranceOrExit = ?? }, obj);

for the two ?? spots, you just need to pass something fitting the data type for those properties, the values will not be used.

This exploits the fact that multiple anonymous types containing the exact same properties, of the same type, in the same order, in the same assembly, will map to the same single type.

However, by this time you should be creating a named type instead.

Lasse V. Karlsen
+1 Just saw that comment on msdn and though how to exploit it - "If two or more anonymous types have the same number and type of properties in the same order, the compiler treats them as the same type and they share the same compiler-generated type information."
Kobi
@Lasse V. Karlsen: Ultimately, cast-by-example is a travesty. You are effectively re-declaring the type at each place outside the method in the module you wish to gain access to it, violating basic principals of reuse.
casperOne
Very nice, but it feels very awkward. Almost evil :)
Philippe Leybaert
I didn't say it was a good idea. I am not sure what you mean by "redeclaring" though, this will internally be created as a single type, used in both the original place and in this place, not as two similar, but distinct, types. But again, it isn't a good idea to do this. It is, however, possible. In other words, the internal code will look like you did: new SomeType { ... }, where "SomeType" is the same in both places.
Lasse V. Karlsen
@Philippe, that's because it is... almost evil that is.
Lasse V. Karlsen
@Lasse V. Karlsen: By "redeclaring", I'm saying that you effectively have to say `new { Member1 = DummyValue, Member2 = DummyValue2, ... }` at *every* point you want to use cast-by-example. Even though it's not a strict type declaration, it falls on the side of being more like a type declaration than it isn't, it's a great deal of extra busy-work for something that can easily be solved by one declaration of a concrete type.
casperOne
That is a very interesting and very evil hack. +1!!
Randolpho
@casperOne, then I agree with you. I would only use this solution if, for some reason, some library gave me back anonymously typed objects. I would not write code like this and pass them around myself.
Lasse V. Karlsen
Whether you want to call this "redeclaring" or by some other name, it still has all the same potential for One Definition Rule violations and resultant breakage as redundant type definitions.
Ben Voigt
+6  A: 

First, you aren't unboxing the type. Anonymous types are reference types, not structures.

Even though you can technically create instances of the same type outside of the method they were declared in (as per section 7.5.10.6 of the C# 3.0 Language Specification, which states:

Within the same program, two anonymous object initializers that specify a sequence of properties of the same names and compile-time types in the same order will produce instances of the same anonymous type.

) you have no way of getting the name of the type, which you need in order to perform the cast from Object back to the type you created. You would have to resort to a cast-by- example solution which is inherently flawed.

Cast-by-example is flawed because from a design standpoint, every single place you want to access the type outside the function it is declared (and still inside the same module), you have to effectively declare the type all over again.

It's a duplication of effort that leads to sloppy design and implementation.

If you are using .NET 4.0, then you could place the object instance in a dynamic variable. However, the major drawback is the lack of compile-time verification of member access. You could easily misspell the name of the member, and then you have a run-time error instead of a compile-time error.

Ultimately, if you find the need to use an anonymous type outside the method it is declared in, then the only good solution is to create a concrete type and substitute the anonymous type for the concrete type.

casperOne