#region " Đ Copyright 2005-07 to Marcos Meli - http://www.marcosmeli.com.ar" // Errors, suggestions, contributions, send a mail to: marcos@filehelpers.com. #endregion using System; using System.Reflection; using System.Text; namespace FileHelpers { /// Base class for all Field Types. Implements all the basic functionality of a field in a typed file. internal abstract class FieldBase { #region " Private & Internal Fields " private static Type strType = typeof (string); internal Type mFieldType; internal bool mIsStringField; internal FieldInfo mFieldInfo; internal TrimMode mTrimMode = TrimMode.None; internal Char[] mTrimChars = null; internal bool mIsOptional = false; internal bool mNextIsOptional = false; internal bool mInNewLine = false; internal bool mIsFirst = false; internal bool mIsLast = false; internal bool mTrailingArray = false; internal object mNullValue = null; //internal bool mNullValueOnWrite = false; #if NET_2_0 private bool mIsNullableType = false; #endif #endregion #region " Constructor " protected FieldBase(FieldInfo fi) { mFieldInfo = fi; mFieldType = mFieldInfo.FieldType; mIsStringField = mFieldType == strType; object[] attribs = fi.GetCustomAttributes(typeof (FieldConverterAttribute), true); if (attribs.Length > 0) { FieldConverterAttribute conv = (FieldConverterAttribute)attribs[0]; mConvertProvider = conv.Converter; conv.ValidateTypes(mFieldInfo); } else mConvertProvider = ConvertHelpers.GetDefaultConverter(fi.Name, mFieldType); if (mConvertProvider != null) mConvertProvider.mDestinationType = fi.FieldType; attribs = fi.GetCustomAttributes(typeof (FieldNullValueAttribute), true); if (attribs.Length > 0) { mNullValue = ((FieldNullValueAttribute) attribs[0]).NullValue; // mNullValueOnWrite = ((FieldNullValueAttribute) attribs[0]).NullValueOnWrite; if (mNullValue != null) { if (! mFieldType.IsAssignableFrom(mNullValue.GetType())) throw new BadUsageException("The NullValue is of type: " + mNullValue.GetType().Name + " that is not asignable to the field " + mFieldInfo.Name + " of type: " + mFieldType.Name); } } #if NET_2_0 mIsNullableType = mFieldType.IsValueType && mFieldType.IsGenericType && mFieldType.GetGenericTypeDefinition() == typeof(Nullable<>); #endif } #endregion private static char[] WhitespaceChars = new char[] { '\t', '\n', '\v', '\f', '\r', ' ', '\x00a0', '\u2000', '\u2001', '\u2002', '\u2003', '\u2004', '\u2005', '\u2006', '\u2007', '\u2008', '\u2009', '\u200a', '\u200b', '\u3000', '\ufeff' }; #region " MustOverride (String Handling) " protected abstract ExtractedInfo ExtractFieldString(LineInfo line); protected abstract void CreateFieldString(StringBuilder sb, object fieldValue); protected string BaseFieldString(object fieldValue) { if (mConvertProvider == null) { if (fieldValue == null) return string.Empty; else return fieldValue.ToString(); // else if (mNullValueOnWrite && fieldValue.Equals(mNullValue)) // res = string.Empty; } else { return mConvertProvider.FieldToString(fieldValue); } } protected int mCharsToDiscard = 0; #endregion internal ConverterBase mConvertProvider; #region " ExtractValue " // object[] values, int index, ForwardReader reader internal object ExtractValue(LineInfo line) { //-> extract only what I need if (this.mInNewLine == true) { if (line.EmptyFromPos() == false) throw new BadUsageException("Text '" + line.CurrentString + "' found before the new line of the field: " + mFieldInfo.Name + " (this is not allowed when you use [FieldInNewLine])"); line.ReLoad(line.mReader.ReadNextLine()); if (line.mLineStr == null) throw new BadUsageException("End of stream found parsing the field " + mFieldInfo.Name + ". Please check the class record."); } ExtractedInfo info = ExtractFieldString(line); if (info.mCustomExtractedString == null) line.mCurrentPos = info.ExtractedTo + 1; line.mCurrentPos += mCharsToDiscard; //total; return AssignFromString(info, line); //-> discard the part that I use //TODO: Uncoment this for Quoted Handling // if (info.NewRestOfLine != null) // { // if (info.NewRestOfLine.Length < CharsToDiscard()) // return info.NewRestOfLine; // else // return info.NewRestOfLine.Substring(CharsToDiscard()); // } // else // { // int total; // if (info.CharsRemoved >= line.mLine.Length) // total = line.mLine.Length; // else // total = info.CharsRemoved + CharsToDiscard(); //return buffer.Substring(total); // } } #region " AssignFromString " internal object AssignFromString(ExtractedInfo fieldString, LineInfo line) { object val; switch (mTrimMode) { case TrimMode.None: break; case TrimMode.Both: fieldString.TrimBoth(mTrimChars); break; case TrimMode.Left: fieldString.TrimStart(mTrimChars); break; case TrimMode.Right: fieldString.TrimEnd(mTrimChars); break; } try { if (mConvertProvider == null) { if (mIsStringField) val = fieldString.ExtractedString(); else { // Trim it to use Convert.ChangeType fieldString.TrimBoth(WhitespaceChars); if (fieldString.Length == 0) { // Empty stand for null val = GetNullValue(); } else { val = Convert.ChangeType(fieldString.ExtractedString(), mFieldType, null); } } } else { if (mConvertProvider.CustomNullHandling == false && fieldString.HasOnlyThisChars(WhitespaceChars)) { val = GetNullValue(); } else { string from = fieldString.ExtractedString(); val = mConvertProvider.StringToField(from); if (val == null) val = GetNullValue(); } } return val; } catch (ConvertException ex) { throw ConvertException.ReThrowException(ex, mFieldInfo.Name, line.mReader.LineNumber, fieldString.ExtractedFrom + 1); } } private object GetNullValue() { if (mNullValue == null) { if (mFieldType.IsValueType) { #if NET_2_0 if ( mIsNullableType ) return null; throw new BadUsageException("Null Value found for the field '" + mFieldInfo.Name + "' in the class '" + mFieldInfo.DeclaringType.Name + "'. You must specify a FieldNullValue attribute because this is a ValueType and canīt be null or you can use the Nullable Types feature of the .NET framework."); #else throw new BadUsageException("Null Value found for the field '" + mFieldInfo.Name + "' in the class '" + mFieldInfo.DeclaringType.Name + "'. You must specify a FieldNullValueAttribute because this is a ValueType and canīt be null."); #endif } else return null; } else return mNullValue; } #endregion #region " CreateValueForField " public object CreateValueForField(object fieldValue) { object val = null; if (fieldValue == null) { if (mNullValue == null) { if (mFieldType.IsValueType) throw new BadUsageException("Null Value found. You must specify a NullValueAttribute in the " + mFieldInfo.Name + " field of type " + mFieldInfo.FieldType.Name + ", because this is a ValueType."); else val = null; } else { val = mNullValue; } } else if (mFieldType == fieldValue) val = fieldValue; else { if (mConvertProvider == null) val = Convert.ChangeType(fieldValue, mFieldType, null); else { try { val = Convert.ChangeType(fieldValue, mFieldType, null); } catch { val = mConvertProvider.StringToField(fieldValue.ToString()); } } } return val; } #endregion #endregion #region " AssignToString " internal void AssignToString(StringBuilder sb, object fieldValue) { if (this.mInNewLine == true) sb.Append(StringHelper.NewLine); CreateFieldString(sb, fieldValue); } #endregion } }