[c#] How to access property of anonymous type in C#?

I have this:

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

nodes.Add(
new {
    Checked     = false,
    depth       = 1,
    id          = "div_" + d.Id
});

... and I'm wondering if I can then grab the "Checked" property of the anonymous object. I'm not sure if this is even possible. Tried doing this:

if (nodes.Any(n => n["Checked"] == false)) ... but it doesn't work.

Thanks

This question is related to c# .net object properties anonymous-types

The answer is


Recently, I had the same problem within .NET 3.5 (no dynamic available). Here is how I solved:

// pass anonymous object as argument
var args = new { Title = "Find", Type = typeof(FindCondition) };

using (frmFind f = new frmFind(args)) 
{
...
...
}

Adapted from somewhere on stackoverflow:

// Use a custom cast extension
public static T CastTo<T>(this Object x, T targetType)
{
   return (T)x;
}

Now get back the object via cast:

public partial class frmFind: Form
{
    public frmFind(object arguments)
    {

        InitializeComponent();

        var args = arguments.CastTo(new { Title = "", Type = typeof(Nullable) });

        this.Text = args.Title;

        ...
    }
    ...
}

If you're storing the object as type object, you need to use reflection. This is true of any object type, anonymous or otherwise. On an object o, you can get its type:

Type t = o.GetType();

Then from that you look up a property:

PropertyInfo p = t.GetProperty("Foo");

Then from that you can get a value:

object v = p.GetValue(o, null);

This answer is long overdue for an update for C# 4:

dynamic d = o;
object v = d.Foo;

And now another alternative in C# 6:

object v = o?.GetType().GetProperty("Foo")?.GetValue(o, null);

Note that by using ?. we cause the resulting v to be null in three different situations!

  1. o is null, so there is no object at all
  2. o is non-null but doesn't have a property Foo
  3. o has a property Foo but its real value happens to be null.

So this is not equivalent to the earlier examples, but may make sense if you want to treat all three cases the same.


You could iterate over the anonymous type's properties using Reflection; see if there is a "Checked" property and if there is then get its value.

See this blog post: http://blogs.msdn.com/wriju/archive/2007/10/26/c-3-0-anonymous-type-and-net-reflection-hand-in-hand.aspx

So something like:

foreach(object o in nodes)
{
    Type t = o.GetType();

    PropertyInfo[] pi = t.GetProperties(); 

    foreach (PropertyInfo p in pi)
    {
        if (p.Name=="Checked" && !(bool)p.GetValue(o))
            Console.WriteLine("awesome!");
    }
}

The accepted answer correctly describes how the list should be declared and is highly recommended for most scenarios.

But I came across a different scenario, which also covers the question asked. What if you have to use an existing object list, like ViewData["htmlAttributes"] in MVC? How can you access its properties (they are usually created via new { @style="width: 100px", ... })?

For this slightly different scenario I want to share with you what I found out. In the solutions below, I am assuming the following declaration for nodes:

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

nodes.Add(
new
{
    Checked = false,
    depth = 1,
    id = "div_1" 
});

1. Solution with dynamic

In C# 4.0 and higher versions, you can simply cast to dynamic and write:

if (nodes.Any(n => ((dynamic)n).Checked == false))
    Console.WriteLine("found a  not checked  element!");

Note: This is using late binding, which means it will recognize only at runtime if the object doesn't have a Checked property and throws a RuntimeBinderException in this case - so if you try to use a non-existing Checked2 property you would get the following message at runtime: "'<>f__AnonymousType0<bool,int,string>' does not contain a definition for 'Checked2'".

2. Solution with reflection

The solution with reflection works both with old and new C# compiler versions. For old C# versions please regard the hint at the end of this answer.

Background

As a starting point, I found a good answer here. The idea is to convert the anonymous data type into a dictionary by using reflection. The dictionary makes it easy to access the properties, since their names are stored as keys (you can access them like myDict["myProperty"]).

Inspired by the code in the link above, I created an extension class providing GetProp, UnanonymizeProperties and UnanonymizeListItems as extension methods, which simplify access to anonymous properties. With this class you can simply do the query as follows:

if (nodes.UnanonymizeListItems().Any(n => (bool)n["Checked"] == false))
{
    Console.WriteLine("found a  not checked  element!");
}

or you can use the expression nodes.UnanonymizeListItems(x => (bool)x["Checked"] == false).Any() as if condition, which filters implicitly and then checks if there are any elements returned.

To get the first object containing "Checked" property and return its property "depth", you can use:

var depth = nodes.UnanonymizeListItems()
             ?.FirstOrDefault(n => n.Contains("Checked")).GetProp("depth");

or shorter: nodes.UnanonymizeListItems()?.FirstOrDefault(n => n.Contains("Checked"))?["depth"];

Note: If you have a list of objects which don't necessarily contain all properties (for example, some do not contain the "Checked" property), and you still want to build up a query based on "Checked" values, you can do this:

if (nodes.UnanonymizeListItems(x => { var y = ((bool?)x.GetProp("Checked", true)); 
                                      return y.HasValue && y.Value == false;}).Any())
{
    Console.WriteLine("found a  not checked   element!");
}

This prevents, that a KeyNotFoundException occurs if the "Checked" property does not exist.


The class below contains the following extension methods:

  • UnanonymizeProperties: Is used to de-anonymize the properties contained in an object. This method uses reflection. It converts the object into a dictionary containing the properties and its values.
  • UnanonymizeListItems: Is used to convert a list of objects into a list of dictionaries containing the properties. It may optionally contain a lambda expression to filter beforehand.
  • GetProp: Is used to return a single value matching the given property name. Allows to treat not-existing properties as null values (true) rather than as KeyNotFoundException (false)

For the examples above, all that is required is that you add the extension class below:

public static class AnonymousTypeExtensions
{
    // makes properties of object accessible 
    public static IDictionary UnanonymizeProperties(this object obj)
    {
        Type type = obj?.GetType();
        var properties = type?.GetProperties()
               ?.Select(n => n.Name)
               ?.ToDictionary(k => k, k => type.GetProperty(k).GetValue(obj, null));
        return properties;
    }
    
    // converts object list into list of properties that meet the filterCriteria
    public static List<IDictionary> UnanonymizeListItems(this List<object> objectList, 
                    Func<IDictionary<string, object>, bool> filterCriteria=default)
    {
        var accessibleList = new List<IDictionary>();
        foreach (object obj in objectList)
        {
            var props = obj.UnanonymizeProperties();
            if (filterCriteria == default
               || filterCriteria((IDictionary<string, object>)props) == true)
            { accessibleList.Add(props); }
        }
        return accessibleList;
    }

    // returns specific property, i.e. obj.GetProp(propertyName)
    // requires prior usage of AccessListItems and selection of one element, because
    // object needs to be a IDictionary<string, object>
    public static object GetProp(this object obj, string propertyName, 
                                 bool treatNotFoundAsNull = false)
    {
        try 
        {
            return ((System.Collections.Generic.IDictionary<string, object>)obj)
                   ?[propertyName];
        }
        catch (KeyNotFoundException)
        {
            if (treatNotFoundAsNull) return default(object); else throw;
        }
    }
}

Hint: The code above is using the null-conditional operators, available since C# version 6.0 - if you're working with older C# compilers (e.g. C# 3.0), simply replace ?. by . and ?[ by [ everywhere (and do the null-handling traditionally by using if statements or catch NullReferenceExceptions), e.g.

var depth = nodes.UnanonymizeListItems()
            .FirstOrDefault(n => n.Contains("Checked"))["depth"];

As you can see, the null-handling without the null-conditional operators would be cumbersome here, because everywhere you removed them you have to add a null check - or use catch statements where it is not so easy to find the root cause of the exception resulting in much more - and hard to read - code.

If you're not forced to use an older C# compiler, keep it as is, because using null-conditionals makes null handling much easier.

Note: Like the other solution with dynamic, this solution is also using late binding, but in this case you're not getting an exception - it will simply not find the element if you're referring to a non-existing property, as long as you keep the null-conditional operators.

What might be useful for some applications is that the property is referred to via a string in solution 2, hence it can be parameterized.


Examples related to c#

How can I convert this one line of ActionScript to C#? Microsoft Advertising SDK doesn't deliverer ads How to use a global array in C#? How to correctly write async method? C# - insert values from file into two arrays Uploading into folder in FTP? Are these methods thread safe? dotnet ef not found in .NET Core 3 HTTP Error 500.30 - ANCM In-Process Start Failure Best way to "push" into C# array

Examples related to .net

You must add a reference to assembly 'netstandard, Version=2.0.0.0 How to use Bootstrap 4 in ASP.NET Core No authenticationScheme was specified, and there was no DefaultChallengeScheme found with default authentification and custom authorization .net Core 2.0 - Package was restored using .NetFramework 4.6.1 instead of target framework .netCore 2.0. The package may not be fully compatible Update .NET web service to use TLS 1.2 EF Core add-migration Build Failed What is the difference between .NET Core and .NET Standard Class Library project types? Visual Studio 2017 - Could not load file or assembly 'System.Runtime, Version=4.1.0.0' or one of its dependencies Nuget connection attempt failed "Unable to load the service index for source" Token based authentication in Web API without any user interface

Examples related to object

How to update an "array of objects" with Firestore? how to remove json object key and value.? Cast object to interface in TypeScript Angular 4 default radio button checked by default How to use Object.values with typescript? How to map an array of objects in React How to group an array of objects by key push object into array Add property to an array of objects access key and value of object using *ngFor

Examples related to properties

Property 'value' does not exist on type 'EventTarget' How to read data from java properties file using Spring Boot Kotlin - Property initialization using "by lazy" vs. "lateinit" react-router - pass props to handler component Specifying trust store information in spring boot application.properties Can I update a component's props in React.js? Property getters and setters Error in Swift class: Property not initialized at super.init call java.util.MissingResourceException: Can't find bundle for base name 'property_file name', locale en_US How to use BeanUtils.copyProperties?

Examples related to anonymous-types

Returning anonymous type in C# How to pass anonymous types as parameters? How to dynamic new Anonymous Class? How to access property of anonymous type in C#? A generic list of anonymous class Accessing constructor of an anonymous class How do I serialize a C# anonymous type to a JSON string? Can anonymous class implement interface?