/// <summary> /// Create a list of fields we are extracting and set /// the size hint for record I/O /// </summary> private void InitRecordFields() { var recordAttribute = Attributes.GetFirstInherited <TypedRecordAttribute>(RecordType); if (recordAttribute == null) { throw new BadUsageException(Messages.Errors.ClassWithOutRecordAttribute .ClassName(RecordType.Name) .Text); } if (ReflectionHelper.GetDefaultConstructor(RecordType) == null) { throw new BadUsageException(Messages.Errors.ClassWithOutDefaultConstructor .ClassName(RecordType.Name) .Text); } Attributes.WorkWithFirst <IgnoreFirstAttribute>( RecordType, a => IgnoreFirst = a.NumberOfLines); Attributes.WorkWithFirst <IgnoreLastAttribute>( RecordType, a => IgnoreLast = a.NumberOfLines); Attributes.WorkWithFirst <IgnoreEmptyLinesAttribute>( RecordType, a => { IgnoreEmptyLines = true; IgnoreEmptySpaces = a.IgnoreSpaces; }); #pragma warning disable CS0618 // Type or member is obsolete Attributes.WorkWithFirst <IgnoreCommentedLinesAttribute>( #pragma warning restore CS0618 // Type or member is obsolete RecordType, a => { IgnoreEmptyLines = true; CommentMarker = a.CommentMarker; CommentAnyPlace = a.AnyPlace; }); Attributes.WorkWithFirst <ConditionalRecordAttribute>( RecordType, a => { RecordCondition = a.Condition; RecordConditionSelector = a.ConditionSelector; if (RecordCondition == RecordCondition.ExcludeIfMatchRegex || RecordCondition == RecordCondition.IncludeIfMatchRegex) { RecordConditionRegEx = new Regex(RecordConditionSelector, RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture); } }); if (CheckInterface(RecordType, typeof(INotifyRead))) { NotifyRead = true; } if (CheckInterface(RecordType, typeof(INotifyWrite))) { NotifyWrite = true; } // Create fields // Search for cached fields var fields = new List <FieldInfo>(ReflectionHelper.RecursiveGetFields(RecordType)); Fields = CreateCoreFields(fields, recordAttribute); if (FieldCount == 0) { throw new BadUsageException(Messages.Errors.ClassWithOutFields .ClassName(RecordType.Name) .Text); } if (recordAttribute is FixedLengthRecordAttribute) { // Defines the initial size of the StringBuilder SizeHint = 0; for (int i = 0; i < FieldCount; i++) { SizeHint += ((FixedLengthField)Fields[i]).FieldLength; } } }
/// <summary> /// Check the Attributes on the field and return a structure containing /// the settings for this file. /// </summary> /// <param name="fi">Information about this field</param> /// <param name="recordAttribute">Type of record we are reading</param> /// <returns>Null if not used</returns> public static FieldBase CreateField(FieldInfo fi, TypedRecordAttribute recordAttribute) { // If ignored, return null #pragma warning disable 612,618 // disable obsole warning if (fi.IsDefined(typeof(FieldNotInFileAttribute), true) || fi.IsDefined(typeof(FieldIgnoredAttribute), true)) #pragma warning restore 612,618 { return(null); } FieldBase res = null; var attributes = (FieldAttribute[])fi.GetCustomAttributes(typeof(FieldAttribute), true); // CHECK USAGE ERRORS !!! // Fixed length record and no attributes at all if (recordAttribute is FixedLengthRecordAttribute && attributes.Length == 0) { throw new BadUsageException("The field: '" + fi.Name + "' must be marked the FieldFixedLength attribute because the record class is marked with FixedLengthRecord."); } if (attributes.Length > 1) { throw new BadUsageException("The field: '" + fi.Name + "' has a FieldFixedLength and a FieldDelimiter attribute."); } if (recordAttribute is DelimitedRecordAttribute && fi.IsDefined(typeof(FieldAlignAttribute), false)) { throw new BadUsageException("The field: '" + fi.Name + "' can't be marked with FieldAlign attribute, it is only valid for fixed length records and are used only for write purpose."); } if (fi.FieldType.IsArray == false && fi.IsDefined(typeof(FieldArrayLengthAttribute), false)) { throw new BadUsageException("The field: '" + fi.Name + "' can't be marked with FieldArrayLength attribute is only valid for array fields."); } // PROCESS IN NORMAL CONDITIONS if (attributes.Length > 0) { FieldAttribute fieldAttb = attributes[0]; if (fieldAttb is FieldFixedLengthAttribute) { // Fixed Field if (recordAttribute is DelimitedRecordAttribute) { throw new BadUsageException("The field: '" + fi.Name + "' can't be marked with FieldFixedLength attribute, it is only for the FixedLengthRecords not for delimited ones."); } var attbFixedLength = (FieldFixedLengthAttribute)fieldAttb; var attbAlign = Attributes.GetFirst <FieldAlignAttribute>(fi); res = new FixedLengthField(fi, attbFixedLength.Length, attbAlign); ((FixedLengthField)res).FixedMode = ((FixedLengthRecordAttribute)recordAttribute).FixedMode; } else if (fieldAttb is FieldDelimiterAttribute) { // Delimited Field if (recordAttribute is FixedLengthRecordAttribute) { throw new BadUsageException("The field: '" + fi.Name + "' can't be marked with FieldDelimiter attribute, it is only for DelimitedRecords not for fixed ones."); } res = new DelimitedField(fi, ((FieldDelimiterAttribute)fieldAttb).Delimiter); } else { throw new BadUsageException("Custom field attributes are not currently supported. Unknown attribute: " + fieldAttb.GetType().Name + " on field: " + fi.Name); } } else // attributes.Length == 0 { var delimitedRecordAttribute = recordAttribute as DelimitedRecordAttribute; if (delimitedRecordAttribute != null) { res = new DelimitedField(fi, delimitedRecordAttribute.Separator); } } if (res != null) { // FieldDiscarded res.Discarded = fi.IsDefined(typeof(FieldValueDiscardedAttribute), false); // FieldTrim Attributes.WorkWithFirst <FieldTrimAttribute>(fi, (x) => { res.TrimMode = x.TrimMode; res.TrimChars = x.TrimChars; }); // FieldQuoted Attributes.WorkWithFirst <FieldQuotedAttribute>(fi, (x) => { if (res is FixedLengthField) { throw new BadUsageException( "The field: '" + fi.Name + "' can't be marked with FieldQuoted attribute, it is only for the delimited records."); } ((DelimitedField)res).QuoteChar = x.QuoteChar; ((DelimitedField)res).QuoteMode = x.QuoteMode; ((DelimitedField)res).QuoteMultiline = x.QuoteMultiline; }); // FieldOrder Attributes.WorkWithFirst <FieldOrderAttribute>(fi, x => res.FieldOrder = x.Order); // FieldOptional res.IsOptional = fi.IsDefined(typeof(FieldOptionalAttribute), false); // FieldInNewLine res.InNewLine = fi.IsDefined(typeof(FieldInNewLineAttribute), false); // FieldArrayLength if (fi.FieldType.IsArray) { res.IsArray = true; res.ArrayType = fi.FieldType.GetElementType(); // MinValue indicates that there is no FieldArrayLength in the array res.ArrayMinLength = int.MinValue; res.ArrayMaxLength = int.MaxValue; Attributes.WorkWithFirst <FieldArrayLengthAttribute>(fi, (x) => { res.ArrayMinLength = x.MinLength; res.ArrayMaxLength = x.MaxLength; if (res.ArrayMaxLength < res.ArrayMinLength || res.ArrayMinLength < 0 || res.ArrayMaxLength <= 0) { throw new BadUsageException("The field: " + fi.Name + " has invalid length values in the [FieldArrayLength] attribute."); } }); } } if (fi.IsDefined(typeof(CompilerGeneratedAttribute), false)) { if (fi.Name.EndsWith("__BackingField") && fi.Name.StartsWith("<") && fi.Name.Contains(">")) { res.FieldFriendlyName = fi.Name.Substring(1, fi.Name.IndexOf(">") - 1); } } if (string.IsNullOrEmpty(res.FieldFriendlyName)) { res.FieldFriendlyName = res.FieldName; } return(res); }