4

I have some sample code looking like this:

var items = new List<object>();

var testObjectOne = new
{
    Valueone = "test1",
    ValueTwo = "test2",
    ValueThree = "test3"
};
var testObjectTwo = new
{
    Valueone = "test1",
    ValueTwo = "test2",
    ValueThree = "test3"
};
items.Add(testObjectOne);
items.Add(testObjectTwo);

foreach (var obj in items)
{
    var val = obj.Valueone;
}

But I can't access Valueone and get the error: object' does not contain a definition for 'Valueone' and no extension method 'Valueone' accepting a first argument of type 'object' could be found (are you missing a using directive or an assembly reference?)

Question: How can i iterate through this list and access ValueOne for example? Any help or input is highly appreciated, thanks

Souvik Ghosh
  • 4,456
  • 13
  • 56
  • 78
Mattias
  • 2,929
  • 5
  • 29
  • 46
  • 1
    `var items = (new[] { testObjectOne }).ToList()`. Or `new List()`. Or a helper method to infer the list type without actually adding objects. Or use tuples. Or, my personal favorite option, don't be lazy and just declare a class. – Jeroen Mostert Aug 11 '17 at 08:31
  • This sounds like a xy-problem. Why don't you create a dedicated type for your testobjects and put the instances in a `List`? – René Vogt Aug 11 '17 at 08:31
  • 1
    The items in your list are of type `object` who doesn't hold a definition for `ValueOne`. You could do something like `var items = Enumerable.Empty().Select(o=>{/*Anonymous definition*/}).ToList()`. – dcg Aug 11 '17 at 08:31

6 Answers6

8

You could use reflection to fetch properties of anonymous types:

var items = new List<object>();

var testObjectOne = new
{
    Valueone = "test1",
    ValueTwo = "test2",
    ValueThree = "test3"
    };
var testObjectTwo = new
{
    Valueone = "test1",
    ValueTwo = "test2",
    ValueThree = "test3"
};
items.Add(testObjectOne);
items.Add(testObjectTwo);

foreach (var obj in items)
{
    var val = obj.GetType()
        .GetProperty("Valueone")
        .GetValue(obj);
}
senz
  • 879
  • 10
  • 25
3

You have to use reflection if you will not cast it back to its original object

System.Reflection.PropertyInfo pi = item.GetType().GetProperty("Valueone");
string Valueone = (string)(pi.GetValue(item, null));

Or you can change the object to dynamic

var items = new List<dynamic>();

var testObjectOne = new
{
    Valueone = "test1",
    ValueTwo = "test2",
    ValueThree = "test3"
};
items.Add(testObjectOne);
items.Add(testObjectTwo);

foreach (var obj in items)
{
    var val = obj.Valueone;
}
Jakub Dąbek
  • 1,044
  • 1
  • 8
  • 17
npo
  • 1,060
  • 8
  • 9
3

Another solution without reflection would be to create a list of anonymous objects like:

var items = Enumerable.Empty<object>().Select(o=>{
                Valueone = "test1",
                ValueTwo = "test2",
                ValueThree = "test3"
            }).ToList();

Edit: Adding an object to the list

items.Add(new {
    Valueone = "Value one",
    ValueTwo = "Value two",
    ValueThree = "Value three"
});

then inside the for the statement var val = obj.Valueone will compile successfully.

dcg
  • 4,187
  • 1
  • 18
  • 32
  • This will just create an empty list of an anonymous type, no way to iterate it. – MakePeaceGreatAgain Aug 25 '17 at 08:23
  • @HimBromBeere In deed. I only pointed out a way to create the list of anonymous objects.I edited my answer to show how to add an item to the list. Thanks. – dcg Sep 01 '17 at 12:10
3

why not create a class to represent these objects?=! It would make your code more solid and you can avoid slow/costly reflection or unsafe /bad practice dynamic acrobatics:

public class TempObject
{
    public string Valueone { get; set; }
    public string ValueTwo { get; set; }
    public string ValueThree { get; set; }
}

var items = new List<TempObject>();

var testObjectOne = new TempObject
{
    Valueone = "test1",
    ValueTwo = "test2",
    ValueThree = "test3"
};

items.Add(testObjectOne);

foreach (var obj in items)
{
    var val = obj.Valueone;
}
Mong Zhu
  • 23,309
  • 10
  • 44
  • 76
3

Simply create your list as of anonymous type also, not as `List:

var list = new[] { new
        {
            Valueone = "test1",
            ValueTwo = "test2",
            ValueThree = "test3"
        },
        new
        {
            Valueone = "test1",
            ValueTwo = "test2",
            ValueThree = "test3"
        }
    }.ToList();

You can even add new elements to the list:

list.Add(new {
    Valueone = "test1",
    ValueTwo = "test2",
    ValueThree = "test3"
});

Now you can easily iterate that array using var:

foreach(var e in list) ...

No need for reflection at all, everything is strongly-typed.

MakePeaceGreatAgain
  • 35,491
  • 6
  • 60
  • 111
1
        //Anonymous object in C#
        var any = new { UserName = "Adel@gmail.com", Password = "P@ssw0rd" };

        //Array of anonymous objects in C#
        object[] defaultUsers = {
            new {UserName = "Adel@gmail.com", Password = "P@ssw0rd" },
            new {UserName = "Mike@gmail.com", Password = "P@ssw0rd" },
            new {UserName = "John@gmail.com", Password = "P@ssw0rd" }
        };

        //Iterate through a list of anonymous objects in C#
        foreach (var user in defaultUsers)
        {
            var userName = user.GetType().GetProperty("UserName").GetValue(user);
            var password = user.GetType().GetProperty("Password").GetValue(user);
        }

So that you better make a model for the data

    public class DefaultUser
{
    public string UserName { get; set; }
    public string Password { get; set; }
    public string Role { get; set; }
}

Then do it this way, that's cleaner

        DefaultUser[] defaultUsers = {
            new DefaultUser() { UserName = "admin@user.com", Password = "P@ssword10", Role = "Admins"},
            new DefaultUser() { UserName = "author@user.com", Password = "P@ssword10", Role="Authors"},
            new DefaultUser() { UserName = "reader@user.com", Password = "P@ssword10", Role="Readers"}};

        foreach (DefaultUser user in defaultUsers)
        {
            var userName = user.UserName;
            var password = user.Password;
        }
Adel Mourad
  • 1,351
  • 16
  • 13