Click here to Skip to main content
15,893,190 members
Articles / Programming Languages / C#
Tip/Trick

Collect values for all instance fields of a given type

Rate me:
Please Sign up or sign in to vote.
2.71/5 (3 votes)
13 Jun 2016CPOL1 min read 6.8K   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:

C++
_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

This article was originally posted at http://pkabir.ru/c-get-instance-fields-particular-type

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer Acumatica
Russian Federation Russian Federation
This member doesn't quite have enough reputation to be able to display their biography and homepage.

Comments and Discussions

 
-- There are no messages in this forum --