简体   繁体   English

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

[英]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. 这里一切都很好,但我应该如何声明这种对象的数组,以及如何建议使用forforeach循环迭代它。

The foreach loop is really the problem I think, because foreach loops expect a declared type. foreach循环实际上是我认为的问题,因为foreach循环期望一个声明的类型。 Still there might be a away, if there is I would to know it too of course. 如果有的话,我当然也会知道它。

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. 您如何建议使用for和foreach循环迭代它。

foreach(var item in array) 
...

or 要么

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

[edit - updated to show population, basic enumeration, etc] [编辑 - 更新以显示人口,基本列举等]

As @Eve says, LINQ is your friend here; 正如@Eve所说,LINQ是你的朋友; 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) (注意:“转储”是由于这是在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);
}

You can use LINQ to achieve what you need. 您可以使用LINQ来实现您的需求。 Here's an example. 这是一个例子。

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

Alternatively, if you just want the array but you don't have the data, you can use this workaround. 或者,如果您只想要阵列但没有数据,则可以使用此解决方法。 However, the result will be an Array , with no information about the type of the elements. 但是,结果将是一个Array ,没有关于元素类型的信息。

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

About iterating, you can use var in your for / foreach loop to avoid the problem of declaring the type. 关于迭代,您可以在for / foreach循环中使用var来避免声明类型的问题。

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

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

EDIT: another workaround to create an empty array with an arbitrary number of elements, based off a sample. 编辑:根据示例创建具有任意数量元素的空数组的另一种解决方法。

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

You can use var in the foreach : 你可以在foreach使用var

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 演示

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM