匿名类型集合?

Posted

技术标签:

【中文标题】匿名类型集合?【英文标题】:Anonymous type collections? 【发布时间】:2010-10-14 06:48:09 【问题描述】:

我正在寻找创建由匿名类型组成的集合的最佳做法。

有几种方法 - this this 线程上的一个和大多数答案假设整个匿名集合可以在一个语句中构建。

由于匿名类型通常用于替换用于存储临时的类(如this SO answer 中提出的),我想避免为匿名集合创建和使用类,正如this post 建议的那样。

在我的例子中,我正在迭代一个集合 - 对于集合中的每个项目,我想以匿名类型(充当元组)收集相关对象。我需要将这些匿名类型放入一个集合中,然后对它们进行排序以供进一步工作。

我考虑过的其他方法:

    使用 object[] 或 ArrayList(失去匿名类型的好处) 为所需项目创建包装类(消除对匿名类型的需求)

这是我的代码中唯一需要这样一个集合的地方 - 最好的方法是什么?

其他信息:

我正在使用旧版 .Net 1.1 对象,因此我使用的集合是实现 IEnumerable 的强类型集合,因此大多数 Linq 扩展方法(例如 .Select)都不起作用:

代码示例

foreach (Item item in myItems)

    foreach (Confirmation confirmation in item.GetConfirmations(true))
    
        if (lastParentId != item.ParentId)
        
            lastParentId = item.ParentId;
            parentObject = new ParentItem(lastParentId);
        

        itemHolder = new ArrayList  item, confirmation ;
        if (parentObject!= null)
        
            itemHolder.Add(parentObject.Rate);
        

        sortConfirmations.Add(confirmation.Date, itemHolder);
    


// Use sortConfirmations

分辨率

我最终使用通用字典将相关项目收集在一起并使用 .OrderBy() 对它们进行排序 - 丑陋,但它有效......并且比现有代码更好。

【问题讨论】:

获取信息;要将 LINQ 与较旧的集合一起使用,请使用 .Cast(),即 myItems.Cast() 等。 【参考方案1】:

如果您对数组感到满意,可以使用数组初始化器:

var items = new[] 
    new  Foo = "def" ,
    new  Foo = "ghi" ,
    new  Foo = "jkl" 
;

如果您想获得List<T>,则可以致电ToList()。由于不需要额外的复制,Marc 的解决方案将比调用 ToList() 稍微高效一些,但我认为在大多数情况下我可能会使用“array and then ToList()”解决方案,因为有更少的混乱。当然,如果性能对于那段代码至关重要,它会改变一些事情。

编辑:当您迭代集合时,只需使用Select

var anonymousItems = items.Select (item => new  Foo=item.Foo, 
                                                 Bar=item.Other )
                          .ToList();

【讨论】:

不能这样做,因为我正在迭代现有集合以检索我想要放入匿名类型的对象。我的意思是收集。添加(anonType)。 一个小提示:数组是只读的,因此如果使用此方法,请考虑调用.ToList() 来生成可写集合。这在诸如扩展方法之类的单元测试场景中非常方便。【参考方案2】:

对于一个非常不同的答案... LINQ?

就我而言,我正在迭代一个 集合 - 对于每个项目 收藏 我想收藏 匿名类型的相关对象 (作为一个元组)。我需要这些 要放入的匿名类型 收集然后对它们进行排序 进一步的工作。

听起来像:

var list = (from item in collection
          from related in item.Relationship
          order by ...something...
          select new item,related).ToList()

【讨论】:

不幸的是,我需要更新一些我将以匿名类型收集的对象。我正在转换一些将这些对象放入 ArrayList 并将每个数组列表放入 SorteList 的现有代码。我需要实现类似但更清洁的目标。 @Oded - 这通常仍然是可能的。当然,如果没有具体的例子,就很难确定... +1 表示“我们需要更多信息”这一点。我强烈怀疑 LINQ 是前进的方向。 它有帮助。谢谢【参考方案3】:

一种选择是使用示例项通过泛型类型推断来创建集合,例如:

    static List<T> CreateEmptyList<T>(T template) 
        return new List<T>();
    
    void Foo() 
        var list = CreateEmptyList(new  Foo = "abc" );
        list.Add(new  Foo = "def" );
        //...
    

您也可以这样做创建一个实例(但使用永远不会得到调用者的匿名方法),但我认为它并不能真正节省任何东西......我们可能不会创建一个实例对象,但我们确实创建了一个委托的实例,所以没有太多的节省......

您还提到了对数据进行排序;请参阅 reply here 以了解将 List&lt;T&gt;.Sort 与 lambda 以及匿名类型一起使用的方法 - 即

list.Sort(x=>x.Foo);

【讨论】:

【参考方案4】:

LINQ 是要走的路。假设您要获取集合 items 中每个项目的相关对象 A、B 和 C,并按相关对象 A 进行排序,您将执行以下操作。

var relatedObjects = items.
       Select(item => new  A = item.A, B = item.B, C = item.C  ).
       OrderBy(item => item.A);

您将获得一组匿名类型的项目,其中三个属性 A、B 和 C 设置为由相关对象 A 排序的相关对象。

我没有验证这一点,但您应该可以稍后扩展 relatedObject 集合。只需执行以下操作即可添加一个新项目。这应该可行,因为如果每个属性的名称和类型匹配,我认为每个程序集只有一个匿名类型。

relatedObjects = relatedObjects.Union(
   Enumerable.Repeat(new  A = someA, B = someB, C = someC , 1))

由于 Enumerable.Repeat() 非常丑陋,但如果您与一组新项目而不是单个新项目联合,则变得非常好。

【讨论】:

【参考方案5】:

我在寻找一种方法来创建临时对象的临时列表时偶然发现了这个问题。 我为什么要创造这样的东西?我正在寻找一种快速的方法来返回 JSON 以获取由另一个对象的某些值组成的对象列表。这就是我的意思。

假设我在服务器端有一个 Employee 类,它在 C# 中如下所示:

public class Employee

          public int Id;
       public int businessGroupId;
       public string title;
       public int positionId;

       public string firstName;
       public string lastName;
       ...

此外,我有一个可以轻松迭代的对象的集合,如下所示:

List<Employee> allEmployees  = new List<Employee>();

现在,我想将员工的整个集合返回到我的调用网页,但我只需要每个人的名字和姓氏。我希望它们以 JSON 形式返回。

重点来了

我不想返回 Employee 对象中的所有属性。

我知道我可以通过遍历 allEmployees 集合并每次构建一个新对象来轻松创建匿名类型。

它看起来像下面这样:

foreach (Employee e in allEmployees)

    var tempObj = new F_Name=e.firstName, L_Name=e.lastName;

什么是匿名类型? :)

现在的诀窍是我想要这些匿名对象的整个集合 (List)。 但是,我无法为 List 提供我将使用的类型。我无法创建 List&lt;unknown&gt; allTempObjects = new List&lt;unknown&gt;();

或者我可以吗?

有了动态,才有可能

我可以做到以下几点,效果很好:

List<dynamic> allEmployees  = new List<dynamic>();

foreach (Employee e in allEmployees)

           var tempObj = new F_Name=e.firstName, L_Name=e.lastName;
        allEmployees.Add(tempObj);


// use the javascript Serializer to serialize the dynamic collection
JavaScriptSerializer jss = new JavaScriptSerializer();
// write the result out to the HTTP Stream (htmlTextWriter in overridden Render method)

 writer.Write(jss.Serialize(allEmployees));

您将在客户端看到如下所示的 JSON:

[
    
      F_Name: "Seth",
      L_Name: "Godin"
    ,
    
       F_Name: "Charles",
       L_Name: "Petzold"
    ,
    
       F_Name: "Jeff",
       L_Name: "Prosise"
    
]

最后,你可能会质疑我为什么要这样做。简单的答案是我想要新的类型,它只用于序列化发送给我的客户。匿名类型和匿名类型的匿名集合的重要原因,你不觉得吗?

【讨论】:

【参考方案6】:

这是一个和最多的答案 线程假设整个匿名 集合可以构建在一个 声明。

是的,您通常在单个语句中创建匿名类型的集合。如果你需要更多的语句,你最终可能会得到一个非常无用的不同匿名类型的集合。

当您在单个语句中创建匿名类型并立即使用它们时,它们很有用。如果集合的创建或进一步的处理有点复杂,匿名类型就会失去一些有用性。例如,您不能有效地将匿名类型传递给方法进行处理,因为该方法不知道对象的类型,因此必须使用反射来从中获取任何东西。

如果您要在此匿名类型集合中重复查找项目,您可能需要创建一个命名类型,以便可以将它们放入字典中以便更快地查找。

【讨论】:

一个 typed 集合,即使是匿名类型,也不会遭受“不同匿名类型的集合”的命运;您不能将“new Foo="acb"”放在“new Bar [int]”的集合中 @Marc Gravell:是的,当然,您需要像 List 这样的东西来处理这两种类型,从而失去与匿名类型信息的直接连接。【参考方案7】:

你可以像这样创建集合

private IList _listeners;

【讨论】:

以上是关于匿名类型集合?的主要内容,如果未能解决你的问题,请参考以下文章

c语言自定义类型——结构体,位段(匿名结构体,结构体的自引用,结构体的内存对齐)

如何获取列表中值的列总数 - 匿名类型的两倍

C#进阶C# 匿名方法

匿名类型与动态类型

Kotlin函数 ⑤ ( 匿名函数变量类型推断 | 匿名函数参数类型自动推断 | 匿名函数又称为 Lambda 表达式 )

C#超级有用的一种类型—匿名类型