创建匿名类型的通用列表有诀窍吗?

时间:2013-04-01 18:39:18

标签: c# generics anonymous-types

有时我需要使用一个元组,例如我有坦克和他们的目标坦克列表(他们追逐他们或类似的东西):

List<Tuple<Tank,Tank>> mylist = new List<Tuple<Tank,Tank>>();

然后当我遍历列表时,我通过

访问它们
mylist[i].item1 ...
mylist[i].item2 ...

这非常令人困惑,我总是忘记什么是item1,什么是item2,如果我可以通过以下方式访问它们:

mylist[i].AttackingTank...
mylist[i].TargetTank...

它会更清楚,有没有办法在没有定义类的情况下完成它:

MyTuple
{
public Tank AttackingTank;
public Tank TargetTank;
}

我想避免定义这个类,因为那时我必须在不同的场景中定义许多不同的类,我可以做一些“技巧”并使这个匿名。

类似的东西:

var k = new {Name = "me", phone = 123};
mylist.Add(k);

当然,我定义它时没有类型传递给List的问题

9 个答案:

答案 0 :(得分:92)

您可以为匿名类型创建一个空列表,然后使用它,享受完整的智能感知和编译时检查:

var list = Enumerable.Empty<object>()
             .Select(r => new {A = 0, B = 0}) // prototype of anonymous type
             .ToList();

list.Add(new { A = 4, B = 5 }); // adding actual values

Console.Write(list[0].A);

答案 1 :(得分:17)

您可以使用List<dynamic>

 var myList = new List<dynamic>();
 myList.Add(new {Tank = new Tank(), AttackingTank = new Tank()});

 Console.WriteLine("AttackingTank: {0}", myList[0].AttackingTank);

答案 2 :(得分:7)

这是一个黑客:

var myList = Enumerable.Empty<int>()
    .Select(dummy => new { AttackingTank = default(Tank), TargetTank = default(Tank), })
    .ToList();

如果Tank是类类型,则可以写(Tank)null而不是default(Tank)。您也可以使用碰巧有的Tank实例。


编辑:

或者:

var myList = Enumerable.Repeat(
    new { AttackingTank = default(Tank), TargetTank = default(Tank), },
    0).ToList();

如果您制作通用方法,则不必使用Enumerable.Empty。它可以是这样的:

static List<TAnon> GetEmptyListWithAnonType<TAnon>(TAnon dummyParameter)
{
    return new List<TAnon>();
}

当使用TAnon从用法推断出来时,就像在:

一样
var myList = GetEmptyListWithAnonType(new { AttackingTank = default(Tank), TargetTank = default(Tank), });

答案 3 :(得分:7)

值得注意的是,最后,有可能使用这样的语法。它已在C#7.0中引入

var tanks = new List<(Tank AttackingTank, Tank TargetTank)>();

(Tank, Tank) tTank = (new Tank(), new Tank());
tanks.Add(tTank);

var a = tanks[0].AttackingTank;
var b = tanks[0].TargetTank;

答案 4 :(得分:5)

你可以使用一个带params的通用方法并返回它:

public static IList<T> ToAnonymousList<T>(params T[] items)
{
  return items;
}

现在你可以说:

var list=ToAnonymousList
(
  new{A=1, B=2},
  new{A=2, B=2}
);

答案 5 :(得分:2)

ExpandoObject怎么样?

dynamic tuple = new ExpandoObject(); 
tuple.WhatEverYouWantTypeOfTank = new Tank(); // Value of any type

<强>编辑:

dynamic tuple = new ExpandoObject();
tuple.AttackingTank = new Tank();
tuple.TargetTank = new Tank();

var mylist = new List<dynamic> { tuple };

//access to items
Console.WriteLine(mylist[0].AttackingTank);

答案 6 :(得分:1)

甚至更简单

        var tupleList = (
           new[] {
                new { fruit = "Tomato", colour = "red"},
                new { fruit = "Tomato", colour = "yellow"},
                new { fruit = "Apple", colour = "red"},
                new { fruit = "Apple", colour = "green"},
                new { fruit = "Medlar", colour = "russet"}
            }).ToList();

失去了静态功能。

答案 7 :(得分:1)

在这里添加一个方便的位。我偶尔会使用亚历克斯的答案,但是当我需要它时,它会让我有点疯狂地尝试追踪它,因为它并不明显(我发现自己正在寻找“新{”)。

所以我添加了以下一些静态方法(我希望我可以使它成为一个扩展方法,但是它的类型是什么?):

public static List<T> CreateEmptyListOf<T>(Func<T> itemCreator)
{
    return Enumerable
        .Empty<object>()
        .Select(o => itemCreator())
        .ToList();
}

这将每次我需要此模式时不同的部分与相同的部分隔离开来。我称之为:

var emptyList = Ext.CreateEmptyListOf(() => new { Name = default(string), SomeInt = default(int) });

答案 8 :(得分:0)

您可以创建对象列表:

List<object> myList = new List<object>();

然后将匿名类型添加到您的列表中:

myList.Add(new {Name = "me", phone = 123});