Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Collect values for all instance fields of a given type

0.00/5 (No votes)
13 Jun 2016 1  
This tip is about how to get collect the values for all instance fields of a given type.

Introduction

This tip is about how to get collect the values for all instance fields of a given type.

Background

While working on TaskMan recently, I have encountered the problem of how to obtain the values for all instance fields of a particular type.

Giving more context: the future versions of TaskMan will make extensive use of command line flagsFor now, I have made up my mind about only a few of them, and declared each flag as an instance field in my main program class (Flag<T> is a simple data structure I use to represent a CLI command flag):

public class TaskMan
{        
    Flag<bool> _displayHelpFlag = new Flag<bool>(nameof(_displayHelpFlag), "?|help");
    Flag<bool> _displayLicenseFlag = new Flag<bool>(nameof(_displayLicenseFlag), "license");
    Flag<bool> _displayVersionFlag = new Flag<bool>(nameof(_displayVersionFlag), "version");

    Flag<string> _priorityFlag = new Flag<string>(nameof(_priorityFlag), "p|priority");
    Flag<string> _descriptionFlag = new Flag<string>(nameof(_descriptionFlag), "d|description");

    // ...
}

At the same time, for one particular purpose irrelevant to the point of this post, I also needed to collect all flags into a collection of the non-generic base class type, Flag.

Of course, at first I wrote something like the following code in the constructor:

public TaskMan(/* arguments irrelevant */)
{
    _flags = new Flag[] 
    {
        _displayHelpFlag,
        _displayLicenseFlag,
        _displayVersionFlag,
        // ...
    };
}

It didn't look good enough. First, it smells of ugly code duplication – I essentially declare things twice. Second, it's bug-prone: what if I add another flag and forget to update the collection in the constructor?

Using the code

So that's what I ended up with, reflection to the rescue:

_flags = typeof(TaskMan)
    .GetFields(BindingFlags.NonPublic | BindingFlags.Instance)
    .Where(fieldInfo => typeof(Flag).IsAssignableFrom(fieldInfo.FieldType))
    .Select(fieldInfo => fieldInfo.GetValue(this))
    .Cast<Flag>();

Note how concise and human-readable this looks using Linq / Lambda syntax! You can even read it out aloud:

  • We ask the type TaskMan:
  • "Get us all your non-public instance fields,
  • where the field type is assignable to a variable of type Flag,
  • collect values from each of these fields,
  • and cast them to the Flag type". 

You can customize this snippet for your needs, substituting the encompassing type name for TaskMan and the desired field type name for Flag

Also, if you're interested in public fields as well, don't forget to remove the BindingFlags.NonPublic from the GetFields call.

History

2016.06.13 – First version of the article

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here