Reputation: 4784
Sometimes i need to use a Tuple, for example i have list of tanks and their target tanks (they chase after them or something like that ) :
List<Tuple<Tank,Tank>> mylist = new List<Tuple<Tank,Tank>>();
and then when i iterate over the list i access them by
mylist[i].item1 ...
mylist[i].item2 ...
It's very confusing and i always forget what is item1 and what is item2, if i could access them by :
mylist[i].AttackingTank...
mylist[i].TargetTank...
It would be much clearer, is there a way to do it without defining a class:
MyTuple
{
public Tank AttackingTank;
public Tank TargetTank;
}
I want to avoid defining this class because then i would have to define many different classes in different scenarios, can i do some "trick" and make this anonymous.
Something like :
var k = new {Name = "me", phone = 123};
mylist.Add(k);
The problem of course that i don't have a type to pass to the List when i define it
Upvotes: 41
Views: 49333
Reputation: 12654
You can create an empty list for anonymous types and then use it, enjoying full intellisense and compile-time checks:
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);
Upvotes: 102
Reputation: 29
You can create a list of objects:
List<object> myList = new List<object>();
Then add the anonymous type to your list:
myList.Add(new {Name = "me", phone = 123});
Upvotes: 0
Reputation: 2105
It's worth to note that finally, there is possibility to use such syntax. It had been introduced in 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;
Upvotes: 9
Reputation: 893
Just to add one more handy bit here. I use Alex's answer on occasion, but it drives me a bit nuts trying to track it back down when I need it, since it's not obvious (I find myself searching for "new {").
So I added the following little static method (I wish I could make it an extension method, but of what type?):
public static List<T> CreateEmptyListOf<T>(Func<T> itemCreator)
{
return Enumerable
.Empty<object>()
.Select(o => itemCreator())
.ToList();
}
This isolates the part that is different each time I need this pattern from those that are the same. I call it like this:
var emptyList = Ext.CreateEmptyListOf(() => new { Name = default(string), SomeInt = default(int) });
Upvotes: 1
Reputation: 116
Or even more simple
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();
Which loses the static function.
Upvotes: 3
Reputation: 62492
You could just have a generic method that takes a params
and returns it:
public static IList<T> ToAnonymousList<T>(params T[] items)
{
return items;
}
So now you can say:
var list=ToAnonymousList
(
new{A=1, B=2},
new{A=2, B=2}
);
Upvotes: 6
Reputation: 61952
Here's a hack:
var myList = Enumerable.Empty<int>()
.Select(dummy => new { AttackingTank = default(Tank), TargetTank = default(Tank), })
.ToList();
If Tank
is a class type, you can write (Tank)null
instead of default(Tank)
. You can also use some Tank
instance you happen to have at hand.
EDIT:
Or:
var myList = Enumerable.Repeat(
new { AttackingTank = default(Tank), TargetTank = default(Tank), },
0).ToList();
If you make a generic method, you won't have to use Enumerable.Empty
. It could go like this:
static List<TAnon> GetEmptyListWithAnonType<TAnon>(TAnon dummyParameter)
{
return new List<TAnon>();
}
It is to be called with the TAnon
inferred from usage, of course, as in:
var myList = GetEmptyListWithAnonType(new { AttackingTank = default(Tank), TargetTank = default(Tank), });
Upvotes: 10
Reputation: 17186
How about ExpandoObject ?
dynamic tuple = new ExpandoObject();
tuple.WhatEverYouWantTypeOfTank = new Tank(); // Value of any type
EDITS:
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);
Upvotes: 2
Reputation: 42497
You could use a List<dynamic>
.
var myList = new List<dynamic>();
myList.Add(new {Tank = new Tank(), AttackingTank = new Tank()});
Console.WriteLine("AttackingTank: {0}", myList[0].AttackingTank);
Upvotes: 18