views:

347

answers:

7

Is there any way to declare a list object of anonymous type. I mean

List<var> someVariable = new List<var>();
someVariable.Add(
             new{Name="Krishna", 
                 Phones = new[] {"555-555-5555", "666-666-6666"}}
                );

This is because I need to create a collection at runtime. Thanks in advance

+10  A: 

It involves a bit of hackery but it can be done.

static List<T> CreateListFromSingle<T>(T value) {
  var list = new List<T>();
  list.Add(value);
  return list;
}

var list = CreateListFromSingle(
   new{Name="Krishna", 
                 Phones = new[] {"555-555-5555", "666-666-6666"}}
                );
JaredPar
Ack. This is clever, and it works, but I'd be so mad if any of my developers ever did this in real work... +1 for the nice trickery, though.
Reed Copsey
@Reed, agreed it's painful to look at but it work
JaredPar
no offense, but I hope he doesn't use this code.. :D
Stan R.
Nice trick, I have never seen this before.
Krishna
@Krishna: For good reason, too ;)
Reed Copsey
How is this any worse than using anonymous types in LINQ?
Robert Davis
+7  A: 

You can't make a collection of an anonymous type like this.

If you need to do this, you'll need to either use List<object>, or make a custom class or struct for your type.


Edit:

I'll rephrase this:

Although, technically, it's possible to make a list of an anonymous type, I would strongly recommend never doing this. There is pretty much always a better approach, as doing this is just making code that is nearly unmaintainable. I highly recommend making a custom type to hold your values instead of using anonymous types.

A custom type will have all of the same capabilities (since anonymous types are defined, by the compiler, at compile time), but will be much more understandable by the developer who follows you...


And just to play, too, here's my entry for "code I'd never actually want to use in the real world":

var customer = new { Name = "Krishna", Phones = new[] { "555-555-5555", "666-666-6666" } };
var someVariable = new[]{1}.Select(i => customer).ToList();
Reed Copsey
Agreed. I think a good rule of thumb is that if you're concerned about the type of an anonymous type object, then you're doing ( or getting ready to ) do something wrong.
kervin
+1 it takes half a second to create a custom type and it saves hours of debugging unmanageable/confusing code.
Stan R.
+1  A: 

I don't think this is possible. Maybe in C# 4 using the dynamic keyword?

Robert Massa
you can, but it wouldn't be a good idea. this is a good example of why some people believe the `dynamic` keyword will be abused.
Stan R.
A: 

I guess i've found what you looking for: http://kirillosenkov.blogspot.com/2008/01/how-to-create-generic-list-of-anonymous.html
It's a technique called casting by example : http://tomasp.net/articles/cannot-return-anonymous-type-from-method.aspx

Thanks for the question, I would never figure that out...
Genius...

NoProblemBabe
+8  A: 

You can make a list like this, but you'll again have to use some serious hackery, and you'll have to use some "type by example" situations. For example:

// create the first list by using a specific "template" type.
var list = new [] { new { Name="", Phones=new[] { "" } } }.ToList();

// clear the list.  The first element was just an example.
list.Clear();

// start adding "actual" values.
list.Add(new { Name = "Krishna", Phones = new[] { "555-555-5555", "666-666-6666" } });
David Morton
Okay - this is, again, clever, and horrifying to watch at the same time... +1
Reed Copsey
Clever, haven't seen that inline trick before
JaredPar
Thank you, I will save it for the future.
Krishna
@kervin, in this case I'm fairly certain the compiler does. If you create two anonymous types which have the same named parameters of the same type there will be a single anonymous type generated. In any case if it doesn't a compile error will be issued for this code
JaredPar
@JaredPar: you're correct. They would be the same type. Thanks.
kervin
+4  A: 

In general you can use the (arguably bad-smelling) cast by example trick others have mentioned to create instances of any generic type parameterized with an anonymous type for the type argument. However, for List<T> there is a slightly less gross way to do it:

var array = new[] {
  new {  
    Name="Krishna",  
    Phones = new[] {"555-555-5555", "666-666-6666"}
  }
};
var list = array.ToList();

Your sketch of a proposed syntax is similar to a feature we did not implement for C# 3 or 4, but we considered. We call the feature "mumble types", and it would go something like this:

List<?> myList = new List<?>() {
  new {  
    Name="Krishna",  
    Phones = new[] {"555-555-5555", "666-666-6666"}
  }
};

We call it "mumble types" because of course you'd read it "myList is a new list of hrmmf". :-)

The idea is that the compiler would look at the initializers and do its best to figure out what the type could possibly be, just the same way as how "var" means "look at the initializer and figure out what the type of the variable is". Whether we'd use "var" as the "mumble" or "?" (which is similar to what Java does in a related feature), or something else is an open question.

In any event, I wouldn't hold my breath waiting for this feature if I were you. It hasn't made the cut for several language versions so far, but it will stay on the list of possibilities for a while longer I think. If, hypothetically speaking, we were to be designing future versions of the language. Which we might or might not be. Remember, Eric's musings about future versions of C# are for entertainment purposes only.

Eric Lippert
+2  A: 

I spent quite a lot of time trying to find a way to save myself some time using a list of anonymous types, then realised it was probably quicker just to use a private class inside the current class...

private class Lookup {
    public int Index;
    public string DocType;
    public string Text;
}
private void MyMethod() {
    List<Lookup> all_lookups = new List<Lookup> {
        new Lookup() {Index=4, DocType="SuperView", Text="SuperView XML File"},
        new Lookup() {Index=2, DocType="Word", Text="Microsoft Word Document"}
    };
    // Use my all_lookups variable here...

}
Jonathan