Populating Object from Text Files via Reflection

Download readfileviareflection.zip

In .Net, an XML file or even a CSV file can easily be mapped to an object using proper attributes. Using the reflected object type, such XML or CSV files can easily be deserialized into the corresponding object.

However, sometimes we do not have the luxury in specifying the format of the data file and beyond the common XML and the less common CSV file format, we rarely use serialization technique to retrieve data from the file. For a concrete example, let’s take a look at the following file that represents a free style inventory list:

;—————- itemName = Pen quantity = 10 ;—————- itemName = Paper color = Red size = A4 quantity = 100 ;—————- itemName = Box size = Large quantity = 20 ;—————- itemName = Ruler length = long quantity = 30 ;—————-

As you can see from the list, each inventory item has a few properties that are a subset of all the available properties. Similar data structures can be found in other real world programs. For example, the INI file structure is similar to the example I gave.

This kind of files is typically processed nonreflectively. We can however, still utilize some features with reflection to make a strongly typed object from the text file.

The first step is to create a value object that holds all the possible keys (sample code in C#):

public class InventoryItem { private string _itemName = null; private string _color = null; . . .

public string ItemName { get { return _itemName; } set { _itemName = value; } } . . .

}

Next we can use a parser to parse the text file line by line and use reflection to populate the class members and thus obtain a strongly-typed object.

public void Parse() {

. . . string line = string.Empty; line = fileStream.ReadLine();

do { if (line == null) break;

if (line.Trim().IndexOf(";—-") == 0) { if (_content == null) { _content = new InventoryItem(); } else { _items.Add(_content); _content = new InventoryItem(); } } else { AddMemberInformation(line); } line = fileStream.ReadLine(); } while (line != null); fileStream.Close(); }

private void AddMemberInformation(string line) { string[] ay = line.Split(‘=’); Type t = _content.GetType(); FieldInfo field = t.GetField(String.Concat("_", ay[0].Trim()), BindingFlags.Instance | BindingFlags.NonPublic);

field.SetValue(_content, ay[1].Trim());

}

The trick used here is in procedure AddMemberInformation(). The private fields are retrieved from the InventoryItem class via Type.GetField. Note that in order to match the private variable names in InventoryItem class, “_” is concatenated with the variable name found in the text file. Also, fields retrieved via reflection are case-sensitive. This might surprise those VB.Net programmers as variables in VB.Net are generally case insensitive.

Be Sociable, Share!

Leave a Reply