Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Declaring and using a array of anonymous objects in C#

How many times we declare a simple class or struct to hold a few properties only to use them only one time when returned by a method. Way too many times I think, thankfully we always have anonymous objects which can be declared in place at run time.

With that thought in mind I would like to know how I can declare one array of such anonymous objects.

Example:

var Employee = new { ID = 5, Name= "Prashant" };

This created a anonymous object with two properties, one being integer and another string.

All good here, but how should I declare a array of this kind of object, and how would you recommend iterating through it with both a for and foreach loops.

The foreach loop is really the problem I think, because foreach loops expect a declared type. Still there might be a away, if there is I would to know it too of course.

like image 980
Fábio Antunes Avatar asked Jan 02 '13 00:01

Fábio Antunes


2 Answers

How many times we declare a simple class or struct to hold a few properties only to use them only one time when returned by a method. Way too many times I think, thankfully we always have anonymous objects which can be declared in place at run time.

Your first and second sentences indicate that you have contradictory purposes in mind. Anonymous types, and hence arrays of anonymous types, cannot easily be returned from a method because there is no way to declare the return type. Try to only use anonymous types for temporary local variables.

With that thought in mind I would like to know how I can declare one array of such anonymous objects.

Like this:

var array = new[] 
  { 
    new { X = 123, Y = 456 }, 
    new { X = 345, Y = 567 } 
  };

how would you recommend iterating through it with both a for and foreach loops.

foreach(var item in array) 
...

or

for (int i = 0; i < array.Length; i += 1)
{
    var item = array[i];
    ...
}
like image 147
Eric Lippert Avatar answered Nov 05 '22 05:11

Eric Lippert


[edit - updated to show population, basic enumeration, etc]

As @Eve says, LINQ is your friend here; as a general rule of thumb, don't try passing anonymous types around - you can, if you're clever - but it's a HUGE pain in the butt to deal with them outside of the context/scope they were declared.

To whit, I decided to see in what ways one could "declare an array of an anonymous type" as a fun thought experiment, and came up with these:

(note: the "Dump" is due to this being written in LINQPad)

// Our anonymous type sequence
var anonymousEnumerable = Enumerable
        .Range(0, 10)
        .Select(i => new { ID = i, Text = i.ToString() });
var enumerableCount = anonymousEnumerable.Count();
var anonymousType = anonymousEnumerable.First().GetType();

// Option #1 - declare it as dynamic, i.e., anything goes
dynamic[] asDynamicArray = new dynamic[enumerableCount];
foreach(var tuple in anonymousEnumerable.Select((item, i) => Tuple.Create(i, item)))
{
    asDynamicArray[tuple.Item1] = tuple.Item2;
}

// Let's go the IEnumerable route
foreach (var asDynamic in asDynamicArray)
{
    Console.WriteLine("ID:{0} Text:{1}", asDynamic.ID, asDynamic.Text);
}

// Lowest common denominator: *everything* is an object
object[] asObjectArray = new object[enumerableCount];
foreach(var tuple in anonymousEnumerable.Select((item, i) => Tuple.Create(i, item)))
{
    asObjectArray[tuple.Item1] = tuple.Item2;
}

// Let's iterate with a for loop - BUT, it's now "untyped", so things get nasty
var idGetterMethod = anonymousType.GetMethod("get_ID");
var textGetterMethod = anonymousType.GetMethod("get_Text");
for(int i=0;i < asObjectArray.Length; i++)
{
    var asObject = asObjectArray[i];
    var id = (int)idGetterMethod.Invoke(asObject, null);
    var text = (string)textGetterMethod.Invoke(asObject, null);
    Console.WriteLine("ID:{0} Text:{1}", id, text);
}

// This is cheating :)
var letTheCompilerDecide = anonymousEnumerable.ToArray();
foreach (var item in letTheCompilerDecide)
{
    Console.WriteLine("ID:{0} Text:{1}", item.ID, item.Text);
}

// Use reflection to "make" an array of the anonymous type
var anonymousArrayType = anonymousType.MakeArrayType();
var reflectIt = Activator.CreateInstance(
          anonymousArrayType, 
          enumerableCount) as Array;    
Array.Copy(anonymousEnumerable.ToArray(), reflectIt, enumerableCount);  

// We're kind of in the same boat as the object array here, since we
// don't really know what the underlying item type is
for(int i=0;i < reflectIt.Length; i++)
{
    var asObject = reflectIt.GetValue(i);
    var id = (int)idGetterMethod.Invoke(asObject, null);
    var text = (string)textGetterMethod.Invoke(asObject, null);
    Console.WriteLine("ID:{0} Text:{1}", id, text);
}
like image 37
JerKimball Avatar answered Nov 05 '22 07:11

JerKimball