As a longtime C++ developer, the only feature I missed in .NET is the ability to have structures/union of character arrays to deal with fixed length field messages. In C++, this feature relies on the ability to directly access memory. FileHelpers gives me a similar capability using reflection and attributes to accomplish this task. You adorn a class and fields with FileHelpers specific attributes and it knows how to do the rest. The FileHelpers documentation is superb, unlike many open source project, so I’ll just include a brief excerpt of the documentation here to whet your appetite.
[FixedLengthRecord()]
public class Customer
{
[FieldFixedLength(5)]
public int CustId;
[FieldFixedLength(20)]
[FieldTrim(TrimMode.Right)]
public string Name;
}
As cool as reflection is, performance is always a potential concern. FileHelpers is a great illustration of how .NET can create highly-performant code. Many times developers, including myself, only think of reflection as a way to access methods, properties, and fields dynamically. Using Reflection.Emit, as FileHelpers does, is a mechanism to allow code to be generated at runtime. Combined with caching, dynamic code generation allows excellent performance.
To work with FileHelpers I create a wrapper around usage of the fixed length record.
using System;
using System.Collections.Generic;
using System.Text;
using FileHelpers;
/// <summary>
/// This generic class provides convenience functions for the FileHelpers library.
/// This class implements the Facade design pattern by encapsulating the FileHelpers
/// engine and providing a simple interface to that functionality.
/// </summary>
/// <typeparam name="T">the class type representing a message. This type must use the
/// FixedLengthRecord attribute</typeparam>
public class FixedLengthMessageParser2<T> where T:class
{
FileHelperEngine engine;
/// <summary>
/// Initializes a new instance of the <see cref="FixedLengthMessageParser<T>"/> class.
/// It creates the file helper object.
/// </summary>
public FixedLengthMessageParser2()
{
engine = new FileHelperEngine(typeof(T));
}
/// <summary>
/// Parses the specified aggregate data.
/// </summary>
/// <param name="aggregateData">The aggregate data.</param>
/// <param name="records">The records found to be contained in the data</param>
/// <param name="resultText">Results of parsing. Empty string if
/// successful, or exception details otherwise</param>
/// <returns>True if able to parse, False otherwise.</returns>
public bool Parse(string aggregateData, out T[] records, out string resultText)
{
records = null;
resultText = String.Empty;
try
{
records = (T[])engine.ReadString(aggregateData);
}
catch (Exception ex)
{
resultText = "entry " + typeof(T) + " [" + aggregateData
+ "]couldn't be read due to error " + ex.ToString();
return false;
}
return true;
}
/// <summary>
/// Provides a string representation of a record.
/// </summary>
/// <param name="msg">The MSG received as input.</param>
/// <returns>String representation of a record.</returns>
public string ReturnToString(T msg)
{
string retVal;
retVal = engine.WriteString(msg.AsEnumerable());
retVal = retVal.Substring(0, retVal.Length - 2); //trim end of line characters
return retVal;
}
/// <summary>
/// Parses a single record
/// </summary>
/// <param name="singleData">A single data record.</param>
/// <param name="fixedLengthRecord">The fixed length record.</param>
/// <param name="resultText">Results of parsing. Empty string if
/// successful, or exception details otherwise</param>
/// <returns></returns>
public bool ParseSingle(string singleData, out T fixedLengthRecord, out string resultText)
{
T [] records = null;
fixedLengthRecord = null;
resultText = String.Empty;
try
{
records = (T[])engine.ReadString(singleData);
if (records.Length == 0)
{
resultText = "entry " + typeof(T) + " [" + singleData
+ "]couldn't be read due to empty data set";
return false;
}
fixedLengthRecord = records[0];
}
catch (Exception ex)
{
resultText = "entry " + typeof(T) + " [" + singleData
+ "]couldn't be read due to error " + ex.ToString();
return false;
}
return true;
}
}
No comments:
Post a Comment