代码之家  ›  专栏  ›  技术社区  ›  Oded

匿名类型集合?

  •  7
  • Oded  · 技术社区  · 17 年前

    我正在寻找从匿名类型创建集合的最佳实践。

    有几种方法- this 一个也是最多的答案 this 线程假定整个匿名集合可以在一条语句中构造。

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

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

    我考虑过的其他办法:

    1. 使用对象[]或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()对它们进行排序-很难看,但它可以工作。。。并且比现有的代码更好。

    6 回复  |  直到 9 年前
        1
  •  25
  •   Jon Skeet    17 年前

    如果您对数组满意,可以使用数组初始值设定项:

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

    然后你可以打电话 ToList() 如果你想得到一个 List<T> 出来Marc的解决方案将比打电话稍微有效一些 托利斯特() 因为不需要额外的复印,但我 认为 在大多数情况下,我可能会使用“array and then ToList()”解决方案,因为这样会减少混乱。当然,如果性能对这段代码至关重要,那么它会改变一些事情。

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

    var anonymousItems = items.Select (item => new { Foo=item.Foo, 
                                                     Bar=item.Other })
                              .ToList();
    
        2
  •  6
  •   Marc Gravell    17 年前

    对于一个非常不同的答案。。。林克?

    集合-用于列表中的每个项目 匿名类型中的相关对象 要放入 收集,然后对其进行排序

    这听起来像:

    var list = (from item in collection
              from related in item.Relationship
              order by ...something...
              select new {item,related}).ToList()
    
        3
  •  4
  •   Community Mohan Dere    9 年前

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

        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<T>.Sort 使用lambda,因此使用匿名类型-即。

    list.Sort(x=>x.Foo);
    
        4
  •  1
  •   Daniel Brückner    17 年前

    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
  •  1
  •   raddevus    12 年前

    我在寻找创建临时对象临时列表的方法时偶然发现了这个问题。 我为什么要创造这样的东西?我正在寻找一种快速的方法来返回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>();
    

    现在,我想回到我的呼叫网页 ,但我 只需要每个人的名字和姓氏

    这是重要的一点

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

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

    它看起来类似于以下内容:

    foreach (Employee e in allEmployees)
    {
        var tempObj = new {F_Name=e.firstName, L_Name=e.lastName};
    }
    

    匿名类型的类型是什么?:)

    现在的诀窍是,我需要这些匿名对象的整个集合(列表<>)。 但是,我没有办法为列表提供我将使用的类型。我无法创建一个 List<unknown> allTempObjects = new List<unknown>();

    或者我可以吗?

    有了动态,这是可能的

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

    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));
    

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

    最后,你可能会问我为什么要这样做。简单的回答是,我想创建一个新类型,它只用于序列化以发送到我的客户机。匿名类型和匿名类型的匿名集合是一个很好的理由,你不这么认为吗?

        6
  •  0
  •   Guffa    17 年前

    这是一个关于这个问题的答案 线程假设整个线程都是匿名的 集合可以一次构造 陈述

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

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

        7
  •  -1
  •   PARUS    6 年前

    私人IList<(字符串名称,bool listenToQueue)>_听众;