在C#中声明和使用匿名对象数组

时间:2013-01-02 00:45:16

标签: c# .net anonymous-types

我们多少次声明一个简单的类或结构来保存一些属性,仅在方法返回时使用它们一次。我想太多次了,谢天谢地我们总是有匿名对象,可以在运行时声明到位。

考虑到这个想法,我想知道如何声明这样一个匿名对象的数组。

示例:

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

这创建了一个具有两个属性的匿名对象,一个是整数,另一个是字符串。

这里一切都很好,但是我应该如何声明这种对象的数组,以及如何建议使用forforeach循环迭代它。

foreach循环确实是我认为的问题,因为foreach循环期望一个声明的类型。如果有的话,我当然也可以知道它。

4 个答案:

答案 0 :(得分:19)

  

我们多少次声明一个简单的类或结构来保存一些属性,仅在方法返回时使用它们一次。我想太多次了,谢天谢地我们总是有匿名对象,可以在运行时声明到位。

你的第一句和第二句表明你的目的是矛盾的。匿名类型以及匿名类型的数组不能轻易地从方法返回,因为无法声明返回类型。尝试仅对临时局部变量使用匿名类型。

  

考虑到这个想法,我想知道如何声明这样一个匿名对象的数组。

像这样:

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

您如何建议使用for和foreach循环迭代它。

foreach(var item in array) 
...

for (int i = 0; i < array.Length; i += 1)
{
    var item = array[i];
    ...
}

答案 1 :(得分:4)

[编辑 - 更新以显示人口,基本列举等]

正如@Eve所说,LINQ是你的朋友;作为一般的经验法则,不要尝试传递匿名类型 - 你可以,如果你聪明 - 但是在上下文/范围之外处理它们的屁股是一个巨大的痛苦他们被宣布了。

对于惠特,我决定用什么方式来“宣布一个匿名类型的数组”作为一个有趣的思想实验,并想出了这些:

(注意:“转储”是由于这是在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);
}

答案 2 :(得分:0)

您可以使用LINQ来实现您的需求。这是一个例子。

int[] ids = {10, 15, 99};
string[] names = {"John", "Phil", "Jack"};
var array = ids.Zip(names, (id, name) => new {ID = id, Name = name}).
                ToArray();

或者,如果您只想要阵列但没有数据,则可以使用此解决方法。但是,结果将是Array,没有关于元素类型的信息。

var sample = new {ID = default(int), Name = default(string)};
var arrayLength = 10;
var array = Array.CreateInstance(sample.GetType(), arrayLength);

关于迭代,您可以在var / for循环中使用foreach来避免声明类型的问题。

foreach (var item in array)
{
    //Do something
}

for (var i = 0; i < array.Length; i++)
{
    var item = array[i];
    //Do something
}

编辑:根据样本创建一个具有任意数量元素的空数组的另一种解决方法。

public static T[] GetArray<T>(T sample, int amount)
{
    return new T[amount];
}

答案 3 :(得分:0)

您可以在var

中使用foreach
var Employee1 = new { ID = 5, Name = "Prashant" };
var Employee2 = new { ID = 1, Name = "Tim" };
var employees = new[] { Employee1, Employee2 };

foreach (var employee in employees)
{
    Console.WriteLine("ID:{0}, Name:{1}", employee.ID, employee.Name);
}

for (int i = 0; i < employees.Length; i++)
{
    Console.WriteLine("ID:{0}, Name:{1}", employees[i].ID, employees[i].Name);
}

Demo