In programming, there are scenarios where dynamically retrieving the value of a property by its name becomes necessary. This guide delves into the intricacies of how to get the value of a property by using its name in C# using reflection. Assuming we have a foundational understanding of C# and reflection, we’ll skip exhaustive explanations of basic concepts. We will set up a simple console application to demonstrate this useful capability in C#.

To download the source code for this article, you can visit our GitHub repository.

Let’s dive in.

Retrieve Property Value By Name

To start, let’s consider a simple Person class:

Support Code Maze on Patreon to get rid of ads and get the best discounts on our products!
Become a patron at Patreon!
public class Person
{
    private Guid _id = Guid.NewGuid();

    public string FirstName { get; set; } = string.Empty;
    public string LastName { get; set; } = string.Empty;
    public int Age { get; set; } = 0;
    public bool IsDeleted { get; set; }
}

We define a Person class with public fields and a single private field. We aim to retrieve property values from an instance of this class dynamically.

To retrieve the value of a public property by its name, let’s create a utility method:

public static bool TryGetPropertyValue<TType, TObj>(TObj obj, string propertyName, out TType? value)
{
    value = default;

    if (obj is null)
    {
        Console.WriteLine("Object is null.");
        return false;
    }

    PropertyInfo? propertyInfo = typeof(TObj).GetProperty(propertyName);

    if (propertyInfo is null)
    {
        Console.WriteLine($"Property '{propertyName}' not found.");
        return false;
    }

    object? propertyValue = propertyInfo.GetValue(obj);

    if (propertyValue is null && Nullable.GetUnderlyingType(typeof(TType)) is not null)
    {
        return true;
    }

    if (propertyValue is not TType typedValue)
    {
        Console.WriteLine($"Property '{propertyName}' is of type {propertyInfo.PropertyType}, got {typeof(TType)}.");
        return false;
    }

    value = typedValue;

    return true;
}

To start with, we define a generic utility method, which means it can return properties of any type. Initially, the method checks if the provided obj object is null. This step is crucial to avoid a NullReferenceException. After ensuring the object is not null, we attempt to retrieve the public property information using reflection with the GetProperty() method. If the property doesn’t exist, we promptly inform the caller and exit gracefully.

Furthermore, it’s important to ensure that the property’s type matches the expected type TType. We achieve this using the is not operator, which checks if the property value can be cast to type TType.

In addition, if the property value is null and the expected type TType is nullable, we handle this scenario correctly. In such a way we ensure that we gracefully manage null values. Finally, if all checks pass, the property value is cast to type TType and assigned to the output parameter, thereby completing the process.

Finally, to test this out, let’s create an instance of the type Person and use our utility method to retrieve the value of Age property:

Person person = new()
{
    FirstName = "Kevin",
    LastName = "Otim",
    Age = 18,
    IsDeleted = false,
};

PropertyRetrieval.TryGetPropertyValue<int, Person>(person, "Age", out var value);

Console.WriteLine($"Retrieved value: {value}.");

We pass the person object and Age string as the property name and we log the result to the console.

Upon inspecting the console, we will observe:

Retrieved value: 18. 

Please note, that the provided TryGetPropertyValue() the method only works for public instance properties retrieval. So, instance and static private properties and protected properties will not be found. To make it work with instance and static private properties and protected properties, we can add BindingFlags to the GetProperty() method call:

PropertyInfo? propertyInfo = typeof(TObj).GetProperty(propertyName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);

Handling Edge Cases

There are cases like property renaming, removal, and changes in type that can pose significant hurdles when trying to retrieve values. We already handled those cases in our method, but let’s just explicitly mention those.

Property Rename or Removal

When we use reflection in C# to access properties, handling scenarios where a property gets renamed or removed is crucial. Let’s consider a situation where we attempt to retrieve a non-existent Address property using our utility method:

PropertyRetrieval.TryGetPropertyValue<string>(person, "Address", out var value);

When we run the program and inspect the console, we will observe:

Property 'Address' not found.

Changing Property Type

Handling changes in property types is crucial, so, let’s test out our utility method for a case where we try to retrieve a property with a wrong type:

PropertyRetrieval.TryGetPropertyValue<string>(person, "IsDeleted", out var value);

Here we attempt to retrieve the value of IsDeleted property as a string type, however, we know IsDeleted is a boolean.

Upon running the program and inspecting the console, we observe the message:

Property 'IsDeleted' is of type System.Boolean, got System.String.

Conclusion

In this guide, we have explored how to get the value of a property by using its name in C#, furthermore, we used a concise and pragmatic approach, moreover, we have considered edge cases and handled them with finesse.

Remember, reflection comes with performance considerations, and its usage should be reasonable. The provided utility method serves as a tool, ready to tackle dynamic property retrieval challenges.

Liked it? Take a second to support Code Maze on Patreon and get the ad free reading experience!
Become a patron at Patreon!