diff --git a/.gitignore b/.gitignore
index 18cfa6839..d5e30466d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -32,4 +32,5 @@ FileHelpers.userprefs
/FileHelpers.Analyzer/FileHelpers.Analyzer/FileHelpers.Analyzer.Vsix/bin
/FileHelpers.Analyzer/FileHelpers.Analyzer/FileHelpers.Analyzer.Vsix/obj
/FileHelpers.Examples/obj
-/FileHelpers.Examples/Release
\ No newline at end of file
+/FileHelpers.Examples/Release
+/_ReSharper.Caches
\ No newline at end of file
diff --git a/FileHelpers.Tests/Data/Good/NumberFormatFrench.txt b/FileHelpers.Tests/Data/Good/NumberFormatFrench.txt
new file mode 100644
index 000000000..afa7b7c8e
--- /dev/null
+++ b/FileHelpers.Tests/Data/Good/NumberFormatFrench.txt
@@ -0,0 +1,3 @@
+10248|32,38|32,38|32,38
+10249|1011,61|1011,61|1011,61
+10250|1 165,83|1 165,83|1 165,83
\ No newline at end of file
diff --git a/FileHelpers.Tests/FileHelpers.Tests.csproj b/FileHelpers.Tests/FileHelpers.Tests.csproj
index 2005f0d42..e5331f0b9 100644
--- a/FileHelpers.Tests/FileHelpers.Tests.csproj
+++ b/FileHelpers.Tests/FileHelpers.Tests.csproj
@@ -165,6 +165,7 @@
+
Code
@@ -509,6 +510,7 @@
+
diff --git a/FileHelpers.Tests/Tests/Converters/DecimalNumbers.cs b/FileHelpers.Tests/Tests/Converters/DecimalNumbers.cs
index e0e6b4b8b..a46228dbd 100644
--- a/FileHelpers.Tests/Tests/Converters/DecimalNumbers.cs
+++ b/FileHelpers.Tests/Tests/Converters/DecimalNumbers.cs
@@ -26,6 +26,10 @@ public void Decimals1()
CheckDecimal((decimal) 81.91, res[9]);
}
+
+
+
+
private static void CheckDecimal(decimal dec, DecimalType res)
{
Assert.AreEqual((decimal) dec, res.DecimalField);
@@ -33,6 +37,7 @@ private static void CheckDecimal(decimal dec, DecimalType res)
Assert.AreEqual((float) dec, res.FloatField);
}
+
[Test]
public void NegativeNumbers()
@@ -65,10 +70,13 @@ public class DecimalType
public decimal DecimalField;
}
+
+
[Test]
public void DecimalsWithExponents()
{
var engine = new FileHelperEngine();
+
DecimalType[] res;
res = TestCommon.ReadTest(engine, "Good", "NumberFormat2.txt");
diff --git a/FileHelpers.Tests/Tests/Converters/DefaultCultureInfo.cs b/FileHelpers.Tests/Tests/Converters/DefaultCultureInfo.cs
new file mode 100644
index 000000000..2fcce02aa
--- /dev/null
+++ b/FileHelpers.Tests/Tests/Converters/DefaultCultureInfo.cs
@@ -0,0 +1,158 @@
+using NUnit.Framework;
+
+namespace FileHelpers.Tests.Converters
+{
+ [TestFixture]
+ public class DefaultCultureInfo
+ {
+ [DelimitedRecord("|")]
+ public class RecordWithoutSpecifiedCulture
+ {
+ public decimal DecimalField;
+ }
+
+ [DelimitedRecord("|", "fr-FR")]
+ public class RecordWithDefaultCulture
+ {
+ public decimal DecimalFieldWithoutCulture;
+
+
+ [FieldConverter(ConverterKind.Decimal, "en-US")]
+ public decimal DecimalFieldWithEnglishCulture;
+ }
+
+ [DelimitedRecord("|")]
+ public class RecordWithFieldCulture
+ {
+ [FieldConverter(ConverterKind.Decimal, "fr-FR")]
+ public decimal DecimalFieldWithFrenchCulture;
+
+ public decimal DecimalFieldWithoutCulture;
+ }
+
+
+ [Test]
+ public void RecordWithoutCultureHasDefaultSeparator()
+ {
+ var engine = new FileHelperEngine();
+ Assert.AreEqual(1, engine.Options.Fields.Count);
+ var decimalConverter = engine.Options.Fields[0].Converter;
+ AssertCanConvertEnglishNumbers(decimalConverter);
+ }
+
+ [Test]
+ public void RecordWithSpecifiedCultureInRecordAttributeUsesThatCultureByDefault()
+ {
+ var engine = new FileHelperEngine();
+ Assert.AreEqual(2, engine.Options.Fields.Count);
+ var decimalConverterWithoutCulture = engine.Options.Fields[0].Converter;
+ AssertCanConvertFrenchNumbers(decimalConverterWithoutCulture);
+
+ var decimalConverterWithEnglishCulture = engine.Options.Fields[1].Converter;
+ AssertCanConvertEnglishNumbers(decimalConverterWithEnglishCulture);
+ }
+
+ [Test]
+ public void FieldWithSpecifiedCultureInFieldConverterAttributeUsesThatCulture()
+ {
+ var engine = new FileHelperEngine();
+ Assert.AreEqual(2, engine.Options.Fields.Count);
+ var decimalConverterWithFrenchCulture = engine.Options.Fields[0].Converter;
+ AssertCanConvertFrenchNumbers(decimalConverterWithFrenchCulture);
+
+ var decimalConverterWithoutCulture = engine.Options.Fields[1].Converter;
+ AssertCanConvertEnglishNumbers(decimalConverterWithoutCulture);
+ }
+
+ #region Helpers
+ private static void AssertCanConvertEnglishNumbers(ConverterBase decimalConverter)
+ {
+ Assert.AreEqual(123.12,
+ decimalConverter.StringToField("123.12"),
+ "If no culture is specified, the decimal separator should be a dot");
+ Assert.AreEqual(1234.12,
+ decimalConverter.StringToField("1,234.12"),
+ "If no culture is specified, the group separator should be a comma");
+ }
+
+ private static void AssertCanConvertFrenchNumbers(ConverterBase decimalConverterWithoutCulture)
+ {
+ Assert.AreEqual(1.23, decimalConverterWithoutCulture.StringToField("1,23"), "If a culture is specified, the decimal separator should be the specified culture decimal separator");
+ Assert.AreEqual(1234.12, decimalConverterWithoutCulture.StringToField("1 234,12"), "If a culture is specified, the group separator should be the specified culture group separator");
+ Assert.Catch(() => { decimalConverterWithoutCulture.StringToField("1.23"); }, "The dot is not a valid french separator");
+ }
+ #endregion
+
+ [DelimitedRecord("|", defaultCultureName: "fr-FR")]
+ public class DecimalTypeWithFrenchConversionAsAWhole
+ {
+ public int IntField;
+ public float FloatField;
+ public double DoubleField;
+ public decimal DecimalField;
+ }
+
+ [DelimitedRecord("|")]
+ public class DecimalTypeWithFrenchConversion
+ {
+ [FieldConverter(ConverterKind.Int32, "fr-FR")]
+ public int IntField;
+ [FieldConverter(ConverterKind.Single, "fr-FR")]
+ public float FloatField;
+ [FieldConverter(ConverterKind.Double, "fr-FR")]
+ public double DoubleField;
+ [FieldConverter(ConverterKind.Decimal, "fr-FR")]
+ public decimal DecimalField;
+ }
+
+ [Test]
+ public void DecimalsWithFrenchCulture()
+ {
+ var engine = new FileHelperEngine();
+ var res = TestCommon.ReadTest(engine, "Good", "NumberFormatFrench.txt");
+
+ Assert.AreEqual(3, res.Length);
+
+ Assert.AreEqual(10248, res[0].IntField);
+ CheckDecimal((decimal)32.38, res[0]);
+
+ Assert.AreEqual(10249, res[1].IntField);
+ CheckDecimal((decimal)1011.61, res[1]);
+
+ Assert.AreEqual(10250, res[2].IntField);
+ CheckDecimal((decimal)1165.83, res[2]);
+ }
+
+ [Test]
+ public void DecimalsWithFrenchCulture2()
+ {
+ var engine = new FileHelperEngine();
+ var res = TestCommon.ReadTest(engine, "Good", "NumberFormatFrench.txt");
+
+ Assert.AreEqual(3, res.Length);
+
+ Assert.AreEqual(10248, res[0].IntField);
+ CheckDecimal((decimal)32.38, res[0]);
+
+ Assert.AreEqual(10249, res[1].IntField);
+ CheckDecimal((decimal)1011.61, res[1]);
+
+ Assert.AreEqual(10250, res[2].IntField);
+ CheckDecimal((decimal)1165.83, res[2]);
+ }
+
+ private static void CheckDecimal(decimal dec, DecimalTypeWithFrenchConversion res)
+ {
+ Assert.AreEqual((decimal)dec, res.DecimalField);
+ Assert.AreEqual((double)dec, res.DoubleField);
+ Assert.AreEqual((float)dec, res.FloatField);
+ }
+
+ private static void CheckDecimal(decimal dec, DecimalTypeWithFrenchConversionAsAWhole res)
+ {
+ Assert.AreEqual((decimal)dec, res.DecimalField);
+ Assert.AreEqual((double)dec, res.DoubleField);
+ Assert.AreEqual((float)dec, res.FloatField);
+ }
+ }
+}
\ No newline at end of file
diff --git a/FileHelpers/Attributes/DelimitedRecordAttribute.cs b/FileHelpers/Attributes/DelimitedRecordAttribute.cs
index 66721c974..f9fd54b99 100644
--- a/FileHelpers/Attributes/DelimitedRecordAttribute.cs
+++ b/FileHelpers/Attributes/DelimitedRecordAttribute.cs
@@ -13,7 +13,8 @@ public sealed class DelimitedRecordAttribute : TypedRecordAttribute
/// Indicates that this class represents a delimited record.
/// The separator string used to split the fields of the record.
- public DelimitedRecordAttribute(string delimiter)
+ /// Default culture name used for each properties if no converter is specified otherwise. If null, the default decimal separator (".") will be used.
+ public DelimitedRecordAttribute(string delimiter, string defaultCultureName = null) : base(defaultCultureName: defaultCultureName)
{
if (Separator != String.Empty)
this.Separator = delimiter;
diff --git a/FileHelpers/Attributes/FixedLengthRecordAttribute.cs b/FileHelpers/Attributes/FixedLengthRecordAttribute.cs
index b955f1c0c..f14784d5d 100644
--- a/FileHelpers/Attributes/FixedLengthRecordAttribute.cs
+++ b/FileHelpers/Attributes/FixedLengthRecordAttribute.cs
@@ -23,7 +23,8 @@ public FixedLengthRecordAttribute()
/// specified variable length record behavior.
///
/// The used for variable length records. By Default is FixedMode.ExactLength
- public FixedLengthRecordAttribute(FixedMode fixedMode)
+ /// Default culture name used for each properties if no converter is specified otherwise. If null, the default decimal separator (".") will be used.
+ public FixedLengthRecordAttribute(FixedMode fixedMode, string defaultCultureName = null) : base(defaultCultureName: defaultCultureName)
{
FixedMode = fixedMode;
}
diff --git a/FileHelpers/Attributes/TypedRecordAttribute.cs b/FileHelpers/Attributes/TypedRecordAttribute.cs
index f42660cf5..e43f6d638 100644
--- a/FileHelpers/Attributes/TypedRecordAttribute.cs
+++ b/FileHelpers/Attributes/TypedRecordAttribute.cs
@@ -10,10 +10,19 @@ namespace FileHelpers
public abstract class TypedRecordAttribute
: Attribute
{
+ ///
+ /// Default culture name used for each properties if no converter is specified otherwise. If null, the default decimal separator (".") will be used.
+ ///
+ public string DefaultCultureName { get; private set; }
+
+
#region " Constructors "
/// Abstract class, see inheritors.
- protected TypedRecordAttribute() {}
+ protected TypedRecordAttribute(string defaultCultureName)
+ {
+ this.DefaultCultureName = defaultCultureName;
+ }
#endregion
}
diff --git a/FileHelpers/Converters/ConvertHelpers.cs b/FileHelpers/Converters/ConvertHelpers.cs
index 0c2b4cc9c..e36b3b4ca 100644
--- a/FileHelpers/Converters/ConvertHelpers.cs
+++ b/FileHelpers/Converters/ConvertHelpers.cs
@@ -1,5 +1,6 @@
using System;
using System.Globalization;
+using System.Linq;
using System.Text;
using FileHelpers.Helpers;
@@ -16,27 +17,43 @@ internal static class ConvertHelpers
{
private const string DefaultDecimalSep = ".";
+ ///
+ /// Array of all allowed decimal separators
+ ///
+ private static readonly string[] mAllowedDecimalSeparators = { ".", "," };
+
#region " CreateCulture "
///
/// Return culture information for with comma decimal separator or comma decimal separator
///
- /// Decimal separator string
+ /// Decimal separator string or culture name
/// Cultural information based on separator
- private static CultureInfo CreateCulture(string decimalSep)
+ private static CultureInfo CreateCulture(string decimalSepOrCultureName)
{
- var ci = new CultureInfo(CultureInfo.CurrentCulture.LCID);
+ CultureInfo ci;
- if (decimalSep == ".") {
- ci.NumberFormat.NumberDecimalSeparator = ".";
- ci.NumberFormat.NumberGroupSeparator = ",";
- }
- else if (decimalSep == ",") {
- ci.NumberFormat.NumberDecimalSeparator = ",";
- ci.NumberFormat.NumberGroupSeparator = ".";
+ if (mAllowedDecimalSeparators.Contains(decimalSepOrCultureName))
+ {
+ ci = new CultureInfo(CultureInfo.CurrentCulture.LCID);
+
+ if (decimalSepOrCultureName == ".")
+ {
+ ci.NumberFormat.NumberDecimalSeparator = ".";
+ ci.NumberFormat.NumberGroupSeparator = ",";
+ }
+ else if (decimalSepOrCultureName == ",")
+ {
+ ci.NumberFormat.NumberDecimalSeparator = ",";
+ ci.NumberFormat.NumberGroupSeparator = ".";
+ }
+ else
+ throw new BadUsageException("You can only use '.' or ',' as decimal or group separators");
}
else
- throw new BadUsageException("You can only use '.' or ',' as decimal or group separators");
+ {
+ ci = CultureInfo.GetCultureInfo(decimalSepOrCultureName);
+ }
return ci;
}
@@ -50,20 +67,23 @@ private static CultureInfo CreateCulture(string decimalSep)
///
/// Field name to check
/// Type of the field to check
+ /// Default culture name used for each properties if no converter is specified otherwise. If null, the default decimal separator (".") will be used.
/// Converter for this particular field
- internal static ConverterBase GetDefaultConverter(string fieldName, Type fieldType)
+ internal static ConverterBase GetDefaultConverter(string fieldName, Type fieldType, string defaultCultureName=null)
{
if (fieldType.IsArray)
{
-
- if (fieldType.GetArrayRank() != 1) {
+
+ if (fieldType.GetArrayRank() != 1)
+ {
throw new BadUsageException("The array field: '" + fieldName +
"' has more than one dimension and is not supported by the library.");
}
fieldType = fieldType.GetElementType();
- if (fieldType.IsArray) {
+ if (fieldType.IsArray)
+ {
throw new BadUsageException("The array field: '" + fieldName +
"' is a jagged array and is not supported by the library.");
}
@@ -71,56 +91,56 @@ internal static ConverterBase GetDefaultConverter(string fieldName, Type fieldTy
if (fieldType.IsValueType &&
fieldType.IsGenericType &&
- fieldType.GetGenericTypeDefinition() == typeof (Nullable<>))
+ fieldType.GetGenericTypeDefinition() == typeof(Nullable<>))
fieldType = fieldType.GetGenericArguments()[0];
// Try to assign a default Converter
- if (fieldType == typeof (string))
+ if (fieldType == typeof(string))
return null;
- if (fieldType == typeof (Int16))
- return new Int16Converter();
+ if (fieldType == typeof(Int16))
+ return new Int16Converter(defaultCultureName ?? DefaultDecimalSep);
- if (fieldType == typeof (Int32))
- return new Int32Converter();
+ if (fieldType == typeof(Int32))
+ return new Int32Converter(defaultCultureName ?? DefaultDecimalSep);
- if (fieldType == typeof (Int64))
- return new Int64Converter();
+ if (fieldType == typeof(Int64))
+ return new Int64Converter(defaultCultureName ?? DefaultDecimalSep);
- if (fieldType == typeof (SByte))
- return new SByteConverter();
+ if (fieldType == typeof(SByte))
+ return new SByteConverter(defaultCultureName ?? DefaultDecimalSep);
- if (fieldType == typeof (UInt16))
- return new UInt16Converter();
+ if (fieldType == typeof(UInt16))
+ return new UInt16Converter(defaultCultureName ?? DefaultDecimalSep);
- if (fieldType == typeof (UInt32))
- return new UInt32Converter();
+ if (fieldType == typeof(UInt32))
+ return new UInt32Converter(defaultCultureName ?? DefaultDecimalSep);
- if (fieldType == typeof (UInt64))
- return new UInt64Converter();
+ if (fieldType == typeof(UInt64))
+ return new UInt64Converter(defaultCultureName ?? DefaultDecimalSep);
- if (fieldType == typeof (byte))
- return new ByteConverter();
+ if (fieldType == typeof(byte))
+ return new ByteConverter(defaultCultureName ?? DefaultDecimalSep);
- if (fieldType == typeof (decimal))
- return new DecimalConverter();
+ if (fieldType == typeof(decimal))
+ return new DecimalConverter(defaultCultureName ?? DefaultDecimalSep);
- if (fieldType == typeof (double))
- return new DoubleConverter();
+ if (fieldType == typeof(double))
+ return new DoubleConverter(defaultCultureName ?? DefaultDecimalSep);
- if (fieldType == typeof (Single))
- return new SingleConverter();
+ if (fieldType == typeof(Single))
+ return new SingleConverter(defaultCultureName ?? DefaultDecimalSep);
- if (fieldType == typeof (DateTime))
- return new DateTimeConverter();
+ if (fieldType == typeof(DateTime))
+ return new DateTimeConverter(ConverterBase.DefaultDateTimeFormat, defaultCultureName);
- if (fieldType == typeof (bool))
+ if (fieldType == typeof(bool))
return new BooleanConverter();
// Added by Alexander Obolonkov 2007.11.08 (the next three)
- if (fieldType == typeof (char))
+ if (fieldType == typeof(char))
return new CharConverter();
- if (fieldType == typeof (Guid))
+ if (fieldType == typeof(Guid))
return new GuidConverter();
if (fieldType.IsEnum)
return new EnumConverter(fieldType);
@@ -151,10 +171,10 @@ internal abstract class CultureConverter
/// Convert to a type given a decimal separator
///
/// type we are converting
- /// Separator
- protected CultureConverter(Type T, string decimalSep)
+ /// Separator or culture name (eg. 'en-US', 'fr-FR'...)
+ protected CultureConverter(Type T, string decimalSepOrCultureName)
{
- mCulture = CreateCulture(decimalSep);
+ mCulture = CreateCulture(decimalSepOrCultureName);
mType = T;
}
@@ -168,7 +188,7 @@ public override sealed string FieldToString(object from)
if (from == null)
return string.Empty;
- return ((IConvertible) from).ToString(mCulture);
+ return ((IConvertible)from).ToString(mCulture);
}
///
@@ -198,14 +218,14 @@ internal sealed class ByteConverter : CultureConverter
/// Convert a string to a byte value using the default decimal separator
///
public ByteConverter()
- : this(DefaultDecimalSep) {}
+ : this(DefaultDecimalSep) { }
///
/// Convert a string to a byte
///
- /// decimal separator to use '.' or ','
- public ByteConverter(string decimalSep)
- : base(typeof (Byte), decimalSep) {}
+ /// decimal separator to use '.' or ','
+ public ByteConverter(string decimalSepOrCultureName)
+ : base(typeof(Byte), decimalSepOrCultureName) { }
///
/// Convert a string to a byte value
@@ -230,14 +250,14 @@ internal sealed class UInt16Converter : CultureConverter
/// Convert a number to a short integer
///
public UInt16Converter()
- : this(DefaultDecimalSep) {}
+ : this(DefaultDecimalSep) { }
///
/// Convert a number to a short integer
///
- /// Decimal separator
- public UInt16Converter(string decimalSep)
- : base(typeof (UInt16), decimalSep) {}
+ /// Decimal separator
+ public UInt16Converter(string decimalSepOrCultureName)
+ : base(typeof(UInt16), decimalSepOrCultureName) { }
///
/// Parse a string to a short integer
@@ -266,14 +286,14 @@ internal sealed class UInt32Converter : CultureConverter
/// Unsigned integer converter
///
public UInt32Converter()
- : this(DefaultDecimalSep) {}
+ : this(DefaultDecimalSep) { }
///
/// Unsigned integer converter with a decimal separator
///
- /// dot or comma for to separate decimal
- public UInt32Converter(string decimalSep)
- : base(typeof (UInt32), decimalSep) {}
+ /// dot or comma for to separate decimal
+ public UInt32Converter(string decimalSepOrCultureName)
+ : base(typeof(UInt32), decimalSepOrCultureName) { }
///
/// Convert a string to a unsigned integer value
@@ -302,14 +322,14 @@ internal sealed class UInt64Converter : CultureConverter
/// Unsigned long converter
///
public UInt64Converter()
- : this(DefaultDecimalSep) {}
+ : this(DefaultDecimalSep) { }
///
/// Unsigned long with decimal separator
///
- /// dot or comma for separator
- public UInt64Converter(string decimalSep)
- : base(typeof (UInt64), decimalSep) {}
+ /// dot or comma for separator
+ public UInt64Converter(string decimalSepOrCultureName)
+ : base(typeof(UInt64), decimalSepOrCultureName) { }
///
/// Convert a string to an unsigned integer long
@@ -342,14 +362,14 @@ internal sealed class SByteConverter : CultureConverter
/// Signed byte converter (8 bit signed integer)
///
public SByteConverter()
- : this(DefaultDecimalSep) {}
+ : this(DefaultDecimalSep) { }
///
/// Signed byte converter (8 bit signed integer)
///
- /// dot or comma for separator
- public SByteConverter(string decimalSep)
- : base(typeof (SByte), decimalSep) {}
+ /// dot or comma for separator
+ public SByteConverter(string decimalSepOrCultureName)
+ : base(typeof(SByte), decimalSepOrCultureName) { }
///
/// Convert a string to an signed byte
@@ -374,14 +394,14 @@ internal sealed class Int16Converter : CultureConverter
/// Convert a value to a short integer
///
public Int16Converter()
- : this(DefaultDecimalSep) {}
+ : this(DefaultDecimalSep) { }
///
/// Convert a value to a short integer
///
- /// dot or comma for separator
- public Int16Converter(string decimalSep)
- : base(typeof (short), decimalSep) {}
+ /// dot or comma for separator
+ public Int16Converter(string decimalSepOrCultureName)
+ : base(typeof(short), decimalSepOrCultureName) { }
///
/// Convert a string to an short integer
@@ -410,14 +430,14 @@ internal sealed class Int32Converter : CultureConverter
/// Convert a value to a integer
///
public Int32Converter()
- : this(DefaultDecimalSep) {}
+ : this(DefaultDecimalSep) { }
///
/// Convert a value to a integer
///
- /// dot or comma for separator
- public Int32Converter(string decimalSep)
- : base(typeof (int), decimalSep) {}
+ /// dot or comma for separator
+ public Int32Converter(string decimalSepOrCultureName)
+ : base(typeof(int), decimalSepOrCultureName) { }
///
/// Convert a string to an integer
@@ -447,14 +467,14 @@ internal sealed class Int64Converter : CultureConverter
/// Convert a value to a long integer
///
public Int64Converter()
- : this(DefaultDecimalSep) {}
+ : this(DefaultDecimalSep) { }
///
/// Convert a value to a long integer
///
- /// dot or comma for separator
- public Int64Converter(string decimalSep)
- : base(typeof (long), decimalSep) {}
+ /// dot or comma for separator
+ public Int64Converter(string decimalSepOrCultureName)
+ : base(typeof(long), decimalSepOrCultureName) { }
///
/// Convert a string to an integer long
@@ -491,14 +511,14 @@ internal sealed class DecimalConverter : CultureConverter
/// Convert a value to a decimal value
///
public DecimalConverter()
- : this(DefaultDecimalSep) {}
+ : this(DefaultDecimalSep) { }
///
/// Convert a value to a decimal value
///
- /// dot or comma for separator
- public DecimalConverter(string decimalSep)
- : base(typeof (decimal), decimalSep) {}
+ /// dot or comma for separator
+ public DecimalConverter(string decimalSepOrCultureName)
+ : base(typeof(decimal), decimalSepOrCultureName) { }
///
/// Convert a string to a decimal
@@ -527,14 +547,14 @@ internal sealed class SingleConverter : CultureConverter
/// Convert a value to a single floating point
///
public SingleConverter()
- : this(DefaultDecimalSep) {}
+ : this(DefaultDecimalSep) { }
///
/// Convert a value to a single floating point
///
- /// dot or comma for separator
- public SingleConverter(string decimalSep)
- : base(typeof (Single), decimalSep) {}
+ /// dot or comma for separator
+ public SingleConverter(string decimalSepOrCultureName)
+ : base(typeof(Single), decimalSepOrCultureName) { }
///
/// Convert a string to an single precision floating point
@@ -563,14 +583,14 @@ internal sealed class DoubleConverter : CultureConverter
/// Convert a value to a floating point
///
public DoubleConverter()
- : this(DefaultDecimalSep) {}
+ : this(DefaultDecimalSep) { }
///
/// Convert a value to a floating point
///
- /// dot or comma for separator
- public DoubleConverter(string decimalSep)
- : base(typeof (Double), decimalSep) {}
+ /// dot or comma for separator
+ public DoubleConverter(string decimalSepOrCultureName)
+ : base(typeof(Double), decimalSepOrCultureName) { }
///
/// Convert a string to an floating point
@@ -602,14 +622,14 @@ internal sealed class PercentDoubleConverter : CultureConverter
/// Convert a value to a floating point from a percentage
///
public PercentDoubleConverter()
- : this(DefaultDecimalSep) {}
+ : this(DefaultDecimalSep) { }
///
/// Convert a value to a floating point from a percentage
///
- /// dot or comma for separator
- public PercentDoubleConverter(string decimalSep)
- : base(typeof (Double), decimalSep) {}
+ /// dot or comma for separator
+ public PercentDoubleConverter(string decimalSepOrCultureName)
+ : base(typeof(Double), decimalSepOrCultureName) { }
///
/// Convert a string to an floating point from percentage
@@ -620,16 +640,18 @@ protected override object ParseString(string from)
{
double res;
var blanksRemoved = StringHelper.RemoveBlanks(from);
- if (blanksRemoved.EndsWith("%")) {
+ if (blanksRemoved.EndsWith("%"))
+ {
if (
!Double.TryParse(blanksRemoved,
NumberStyles.Number | NumberStyles.AllowExponent,
mCulture,
out res))
throw new ConvertException(from, mType);
- return res/100.0;
+ return res / 100.0;
}
- else {
+ else
+ {
if (
!Double.TryParse(blanksRemoved,
NumberStyles.Number | NumberStyles.AllowExponent,
@@ -661,14 +683,14 @@ internal sealed class DateTimeConverter : ConverterBase
/// Convert a value to a date time value
///
public DateTimeConverter()
- : this(DefaultDateTimeFormat) {}
+ : this(DefaultDateTimeFormat) { }
///
/// Convert a value to a date time value
///
/// date format see .Net documentation
public DateTimeConverter(string format)
- :this(format, null)
+ : this(format, null)
{
}
@@ -706,7 +728,8 @@ public override object StringToField(string from)
from = string.Empty;
DateTime val;
- if (!DateTime.TryParseExact(from.Trim(), mFormat, mCulture, DateTimeStyles.None, out val)) {
+ if (!DateTime.TryParseExact(from.Trim(), mFormat, mCulture, DateTimeStyles.None, out val))
+ {
string extra;
if (from.Length > mFormat.Length)
@@ -717,7 +740,7 @@ public override object StringToField(string from)
extra = " Using the format: '" + mFormat + "'";
- throw new ConvertException(from, typeof (DateTime), extra);
+ throw new ConvertException(from, typeof(DateTime), extra);
}
return val;
}
@@ -752,13 +775,13 @@ internal sealed class DateTimeMultiFormatConverter : ConverterBase
/// Convert a value to a date time value using multiple formats
///
public DateTimeMultiFormatConverter(string format1, string format2)
- : this(new[] {format1, format2}) {}
+ : this(new[] { format1, format2 }) { }
///
/// Convert a value to a date time value using multiple formats
///
public DateTimeMultiFormatConverter(string format1, string format2, string format3)
- : this(new[] {format1, format2, format3}) {}
+ : this(new[] { format1, format2, format3 }) { }
///
/// Convert a date time value to a string
@@ -766,15 +789,18 @@ public DateTimeMultiFormatConverter(string format1, string format2, string forma
/// list of formats to try
private DateTimeMultiFormatConverter(string[] formats)
{
- for (int i = 0; i < formats.Length; i++) {
+ for (int i = 0; i < formats.Length; i++)
+ {
if (formats[i] == null ||
formats[i] == String.Empty)
throw new BadUsageException("The format of the DateTime Converter can be null or empty.");
- try {
+ try
+ {
DateTime.Now.ToString(formats[i]);
}
- catch {
+ catch
+ {
throw new BadUsageException("The format: '" + formats[i] +
" is invalid for the DateTime Converter.");
}
@@ -794,9 +820,10 @@ public override object StringToField(string from)
from = string.Empty;
DateTime val;
- if (!DateTime.TryParseExact(from.Trim(), mFormats, null, DateTimeStyles.None, out val)) {
+ if (!DateTime.TryParseExact(from.Trim(), mFormats, null, DateTimeStyles.None, out val))
+ {
string extra = " does not match any of the given formats: " + CreateFormats();
- throw new ConvertException(from, typeof (DateTime), extra);
+ throw new ConvertException(from, typeof(DateTime), extra);
}
return val;
}
@@ -809,7 +836,8 @@ private string CreateFormats()
{
var sb = new StringBuilder();
- for (int i = 0; i < mFormats.Length; i++) {
+ for (int i = 0; i < mFormats.Length; i++)
+ {
if (i == 0)
sb.Append("'" + mFormats[i] + "'");
else
@@ -854,7 +882,7 @@ internal sealed class BooleanConverter : ConverterBase
///
/// Simple boolean converter
///
- public BooleanConverter() {}
+ public BooleanConverter() { }
///
/// Boolean converter with true false values
@@ -879,9 +907,11 @@ public override object StringToField(string from)
object val;
string testTo = from.ToLower();
- if (mTrueString == null) {
+ if (mTrueString == null)
+ {
testTo = testTo.Trim();
- switch (testTo) {
+ switch (testTo)
+ {
case "true":
case "1":
case "y":
@@ -894,35 +924,38 @@ public override object StringToField(string from)
case "n":
case "f":
- // I don't think that this case is possible without overriding the CustomNullHandling
- // and it is possible that defaulting empty fields to be false is not correct
+ // I don't think that this case is possible without overriding the CustomNullHandling
+ // and it is possible that defaulting empty fields to be false is not correct
case "":
val = false;
break;
default:
throw new ConvertException(from,
- typeof (bool),
+ typeof(bool),
"The string: " + from
+ " can't be recognized as boolean using default true/false values.");
}
}
- else {
+ else
+ {
// Most of the time the strings should match exactly. To improve performance
// we skip the trim if the exact match is true
if (testTo == mTrueStringLower)
val = true;
else if (testTo == mFalseStringLower)
val = false;
- else {
+ else
+ {
testTo = testTo.Trim();
if (testTo == mTrueStringLower)
val = true;
else if (testTo == mFalseStringLower)
val = false;
- else {
+ else
+ {
throw new ConvertException(from,
- typeof (bool),
+ typeof(bool),
"The string: " + from
+ " can't be recognized as boolean using the true/false values: " + mTrueString + "/" +
mFalseString);
@@ -941,7 +974,8 @@ public override object StringToField(string from)
public override string FieldToString(object from)
{
bool b = Convert.ToBoolean(from);
- if (b) {
+ if (b)
+ {
if (mTrueString == null)
return "True";
else
@@ -999,7 +1033,7 @@ private enum CharFormat
///
public CharConverter()
: this("") // default, no upper or lower case conversion
- {}
+ { }
///
/// Single character converter that optionally makes it upper (X) or lower case (x)
@@ -1007,7 +1041,8 @@ public CharConverter()
/// empty string for no upper or lower, x for lower case, X for Upper case
public CharConverter(string format)
{
- switch (format.Trim()) {
+ switch (format.Trim())
+ {
case "x":
case "lower":
mFormat = CharFormat.Lower;
@@ -1038,8 +1073,10 @@ public override object StringToField(string from)
if (string.IsNullOrEmpty(from))
return Char.MinValue;
- try {
- switch (mFormat) {
+ try
+ {
+ switch (mFormat)
+ {
case CharFormat.NoChange:
return from[0];
@@ -1051,12 +1088,13 @@ public override object StringToField(string from)
default:
throw new ConvertException(from,
- typeof (Char),
+ typeof(Char),
"Unknown char convert flag " + mFormat.ToString());
}
}
- catch {
- throw new ConvertException(from, typeof (Char), "Upper or lower case of input string failed");
+ catch
+ {
+ throw new ConvertException(from, typeof(Char), "Upper or lower case of input string failed");
}
}
@@ -1067,7 +1105,8 @@ public override object StringToField(string from)
/// String containing the character
public override string FieldToString(object from)
{
- switch (mFormat) {
+ switch (mFormat)
+ {
case CharFormat.NoChange:
return Convert.ToChar(from).ToString();
@@ -1078,7 +1117,7 @@ public override string FieldToString(object from)
return char.ToUpper(Convert.ToChar(from)).ToString();
default:
- throw new ConvertException("", typeof (Char), "Unknown char convert flag " + mFormat.ToString());
+ throw new ConvertException("", typeof(Char), "Unknown char convert flag " + mFormat.ToString());
}
}
}
@@ -1098,7 +1137,7 @@ internal sealed class GuidConverter : ConverterBase
///
public GuidConverter()
: this("D") // D or N or B or P (default is D: see Guid.ToString(string format))
- {}
+ { }
///
/// Create a GUID converter with formats as defined for GUID
@@ -1128,11 +1167,13 @@ public override object StringToField(string from)
if (String.IsNullOrEmpty(from))
return Guid.Empty;
- try {
+ try
+ {
return new Guid(from);
}
- catch {
- throw new ConvertException(from, typeof (Guid));
+ catch
+ {
+ throw new ConvertException(from, typeof(Guid));
}
}
@@ -1145,7 +1186,7 @@ public override string FieldToString(object from)
{
if (from == null)
return String.Empty;
- return ((Guid) from).ToString(mFormat);
+ return ((Guid)from).ToString(mFormat);
}
}
diff --git a/FileHelpers/Enums/ConverterKind.cs b/FileHelpers/Enums/ConverterKind.cs
index fd7516a70..c3dc77e89 100644
--- a/FileHelpers/Enums/ConverterKind.cs
+++ b/FileHelpers/Enums/ConverterKind.cs
@@ -23,74 +23,74 @@ public enum ConverterKind
///
/// Convert from or to Byte values.
- /// Params: arg1 is the decimal separator, by default '.'
+ /// Params: arg1 is either a decimal separator, by default '.', or a culture name (eg. "en-US", "fr-FR")
///
Byte,
///
/// Convert from or to Int16 or short values.
- /// Params: arg1 is the decimal separator, by default '.'
+ /// Params: arg1 is either a decimal separator, by default '.', or a culture name (eg. "en-US", "fr-FR")
///
Int16,
///
/// Convert from or to Int32 or int values.
- /// Params: arg1 is the decimal separator, by default '.'
+ /// Params: arg1 is either a decimal separator, by default '.', or a culture name (eg. "en-US", "fr-FR")
///
Int32,
///
/// Convert from or to Int64 or long values.
- /// Params: arg1 is the decimal separator, by default '.'
+ /// Params: arg1 is either a decimal separator, by default '.', or a culture name (eg. "en-US", "fr-FR")
///
Int64,
///
/// Convert from or to Decimal values.
- /// Params: arg1 is the decimal separator, by default '.'
+ /// Params: arg1 is either a decimal separator, by default '.', or a culture name (eg. "en-US", "fr-FR")
///
Decimal,
///
/// Convert from or to Double values.
- /// Params: arg1 is the decimal separator, by default '.'
+ /// Params: arg1 is either a decimal separator, by default '.', or a culture name (eg. "en-US", "fr-FR")
///
Double,
//Added by Shreyas Narasimhan (17 March 2010)
///
/// Convert from or to Double values. Understands Percent '%' symbol
/// and if present returns number /100 only while reading
- /// Params: arg1 is the decimal separator, by default '.'
+ /// Params: arg1 is either a decimal separator, by default '.', or a culture name (eg. "en-US", "fr-FR")
///
PercentDouble,
///
/// Convert from or to Single values.
- /// Params: arg1 is the decimal separator, by default '.'
+ /// Params: arg1 is either a decimal separator, by default '.', or a culture name (eg. "en-US", "fr-FR")
///
Single,
///
/// Convert from or to Byte values.
- /// Params: arg1 is the decimal separator, by default '.'
+ /// Params: arg1 is either a decimal separator, by default '.', or a culture name (eg. "en-US", "fr-FR")
///
SByte,
///
/// Convert from or to UInt16 or unsigned short values.
- /// Params: arg1 is the decimal separator, by default '.'
+ /// Params: arg1 is either a decimal separator, by default '.', or a culture name (eg. "en-US", "fr-FR")
///
UInt16,
///
/// Convert from or to UInt32 or unsigned int values.
- /// Params: arg1 is the decimal separator, by default '.'
+ /// Params: arg1 is either a decimal separator, by default '.', or a culture name (eg. "en-US", "fr-FR")
///
UInt32,
///
/// Convert from or to UInt64 or unsigned long values.
- /// Params: arg1 is the decimal separator, by default '.'
+ /// Params: arg1 is either a decimal separator, by default '.', or a culture name (eg. "en-US", "fr-FR")
///
UInt64,
diff --git a/FileHelpers/Fields/DelimitedField.cs b/FileHelpers/Fields/DelimitedField.cs
index c94918fff..93142e5e5 100644
--- a/FileHelpers/Fields/DelimitedField.cs
+++ b/FileHelpers/Fields/DelimitedField.cs
@@ -25,8 +25,9 @@ private DelimitedField() {}
///
/// field info structure
/// field separator
- internal DelimitedField(FieldInfo fi, string sep)
- : base(fi)
+ /// Default culture name used for each properties if no converter is specified otherwise. If null, the default decimal separator (".") will be used.
+ internal DelimitedField(FieldInfo fi, string sep, string defaultCultureName=null)
+ : base(fi,defaultCultureName)
{
QuoteChar = '\0';
QuoteMultiline = MultilineMode.AllowForBoth;
diff --git a/FileHelpers/Fields/FieldBase.cs b/FileHelpers/Fields/FieldBase.cs
index ec357735d..6faf7ebd6 100644
--- a/FileHelpers/Fields/FieldBase.cs
+++ b/FileHelpers/Fields/FieldBase.cs
@@ -185,8 +185,8 @@ public static FieldBase CreateField(FieldInfo fi, TypedRecordAttribute recordAtt
var memberName = "The field: '" + fi.Name;
Type fieldType = fi.FieldType;
string fieldFriendlyName = AutoPropertyName(fi);
- if (string.IsNullOrEmpty(fieldFriendlyName)==false)
- {
+ if (string.IsNullOrEmpty(fieldFriendlyName) == false)
+ {
var prop = fi.DeclaringType.GetProperty(fieldFriendlyName);
if (prop != null)
{
@@ -200,67 +200,82 @@ public static FieldBase CreateField(FieldInfo fi, TypedRecordAttribute recordAtt
}
// If ignored, return null
#pragma warning disable 612,618 // disable obsolete warning
- if (mi.IsDefined(typeof (FieldNotInFileAttribute), true) ||
- mi.IsDefined(typeof (FieldIgnoredAttribute), true) ||
- mi.IsDefined(typeof (FieldHiddenAttribute), true))
+ if (mi.IsDefined(typeof(FieldNotInFileAttribute), true) ||
+ mi.IsDefined(typeof(FieldIgnoredAttribute), true) ||
+ mi.IsDefined(typeof(FieldHiddenAttribute), true))
#pragma warning restore 612,618
return null;
- var attributes = (FieldAttribute[]) mi.GetCustomAttributes(typeof (FieldAttribute), true);
+ var attributes = (FieldAttribute[])mi.GetCustomAttributes(typeof(FieldAttribute), true);
// CHECK USAGE ERRORS !!!
// Fixed length record and no attributes at all
if (recordAttribute is FixedLengthRecordAttribute &&
- attributes.Length == 0) {
+ attributes.Length == 0)
+ {
throw new BadUsageException(memberName +
"' must be marked the FieldFixedLength attribute because the record class is marked with FixedLengthRecord.");
}
- if (attributes.Length > 1) {
+ if (attributes.Length > 1)
+ {
throw new BadUsageException(memberName +
"' has a FieldFixedLength and a FieldDelimiter attribute.");
}
if (recordAttribute is DelimitedRecordAttribute &&
- mi.IsDefined(typeof (FieldAlignAttribute), false)) {
+ mi.IsDefined(typeof(FieldAlignAttribute), false))
+ {
throw new BadUsageException(memberName +
"' can't be marked with FieldAlign attribute, it is only valid for fixed length records and are used only for write purpose.");
}
if (fieldType.IsArray == false &&
- mi.IsDefined(typeof (FieldArrayLengthAttribute), false)) {
+ mi.IsDefined(typeof(FieldArrayLengthAttribute), false))
+ {
throw new BadUsageException(memberName +
"' can't be marked with FieldArrayLength attribute is only valid for array fields.");
}
// PROCESS IN NORMAL CONDITIONS
- if (attributes.Length > 0) {
+ if (attributes.Length > 0)
+ {
FieldAttribute fieldAttb = attributes[0];
- if (fieldAttb is FieldFixedLengthAttribute) {
+ if (fieldAttb is FieldFixedLengthAttribute)
+ {
// Fixed Field
- if (recordAttribute is DelimitedRecordAttribute) {
+ if (recordAttribute is DelimitedRecordAttribute)
+ {
throw new BadUsageException(memberName +
"' can't be marked with FieldFixedLength attribute, it is only for the FixedLengthRecords not for delimited ones.");
}
- var attbFixedLength = (FieldFixedLengthAttribute) fieldAttb;
+ var attbFixedLength = (FieldFixedLengthAttribute)fieldAttb;
var attbAlign = Attributes.GetFirst(mi);
- res = new FixedLengthField(fi, attbFixedLength.Length, attbAlign);
- ((FixedLengthField) res).FixedMode = ((FixedLengthRecordAttribute) recordAttribute).FixedMode;
+ res = new FixedLengthField(fi,
+ attbFixedLength.Length,
+ attbAlign,
+ recordAttribute.DefaultCultureName);
+ ((FixedLengthField)res).FixedMode = ((FixedLengthRecordAttribute)recordAttribute).FixedMode;
}
- else if (fieldAttb is FieldDelimiterAttribute) {
+ else if (fieldAttb is FieldDelimiterAttribute)
+ {
// Delimited Field
- if (recordAttribute is FixedLengthRecordAttribute) {
+ if (recordAttribute is FixedLengthRecordAttribute)
+ {
throw new BadUsageException(memberName +
"' can't be marked with FieldDelimiter attribute, it is only for DelimitedRecords not for fixed ones.");
}
- res = new DelimitedField(fi, ((FieldDelimiterAttribute) fieldAttb).Delimiter);
+ res = new DelimitedField(fi,
+ ((FieldDelimiterAttribute)fieldAttb).Delimiter,
+ recordAttribute.DefaultCultureName);
}
- else {
+ else
+ {
throw new BadUsageException(
"Custom field attributes are not currently supported. Unknown attribute: " +
fieldAttb.GetType().Name + " on field: " + fi.Name);
@@ -272,35 +287,41 @@ public static FieldBase CreateField(FieldInfo fi, TypedRecordAttribute recordAtt
if (delimitedRecordAttribute != null)
{
- res = new DelimitedField(fi, delimitedRecordAttribute.Separator);
+ res = new DelimitedField(fi,
+ delimitedRecordAttribute.Separator,
+ recordAttribute.DefaultCultureName);
}
}
- if (res != null) {
+ if (res != null)
+ {
// FieldDiscarded
- res.Discarded = mi.IsDefined(typeof (FieldValueDiscardedAttribute), false);
+ res.Discarded = mi.IsDefined(typeof(FieldValueDiscardedAttribute), false);
// FieldTrim
Attributes.WorkWithFirst(mi,
- (x) => {
+ (x) =>
+ {
res.TrimMode = x.TrimMode;
res.TrimChars = x.TrimChars;
});
// FieldQuoted
Attributes.WorkWithFirst(mi,
- (x) => {
- if (res is FixedLengthField) {
+ (x) =>
+ {
+ if (res is FixedLengthField)
+ {
throw new BadUsageException(
memberName +
"' can't be marked with FieldQuoted attribute, it is only for the delimited records.");
}
- ((DelimitedField) res).QuoteChar =
+ ((DelimitedField)res).QuoteChar =
x.QuoteChar;
- ((DelimitedField) res).QuoteMode =
+ ((DelimitedField)res).QuoteMode =
x.QuoteMode;
- ((DelimitedField) res).QuoteMultiline =
+ ((DelimitedField)res).QuoteMultiline =
x.QuoteMultiline;
});
@@ -320,7 +341,8 @@ public static FieldBase CreateField(FieldInfo fi, TypedRecordAttribute recordAtt
res.IsNotEmpty = mi.IsDefined(typeof(FieldNotEmptyAttribute), false);
// FieldArrayLength
- if (fieldType.IsArray) {
+ if (fieldType.IsArray)
+ {
res.IsArray = true;
res.ArrayType = fieldType.GetElementType();
@@ -329,13 +351,15 @@ public static FieldBase CreateField(FieldInfo fi, TypedRecordAttribute recordAtt
res.ArrayMaxLength = int.MaxValue;
Attributes.WorkWithFirst(mi,
- (x) => {
+ (x) =>
+ {
res.ArrayMinLength = x.MinLength;
res.ArrayMaxLength = x.MaxLength;
if (res.ArrayMaxLength < res.ArrayMinLength ||
res.ArrayMinLength < 0 ||
- res.ArrayMaxLength <= 0) {
+ res.ArrayMaxLength <= 0)
+ {
throw new BadUsageException(memberName +
" has invalid length values in the [FieldArrayLength] attribute.");
}
@@ -360,8 +384,9 @@ internal static string AutoPropertyName(FieldInfo fi)
fi.Name.StartsWith("<") &&
fi.Name.Contains(">"))
return fi.Name.Substring(1, fi.Name.IndexOf(">") - 1);
-
+
}
+
return "";
}
@@ -390,10 +415,11 @@ internal FieldBase()
/// Verify the settings against the actual field to ensure it will work.
///
/// Field Info Object
- internal FieldBase(FieldInfo fi)
+ /// Default culture name used for each properties if no converter is specified otherwise. If null, the default decimal separator (".") will be used.
+ internal FieldBase(FieldInfo fi, string defaultCultureName = null)
: this()
{
-
+
FieldInfo = fi;
FieldType = FieldInfo.FieldType;
MemberInfo attibuteTarget = fi;
@@ -416,28 +442,34 @@ internal FieldBase(FieldInfo fi)
else
FieldTypeInternal = FieldType;
- IsStringField = FieldTypeInternal == typeof (string);
+ IsStringField = FieldTypeInternal == typeof(string);
- object[] attribs = attibuteTarget.GetCustomAttributes(typeof (FieldConverterAttribute), true);
+ object[] attribs = attibuteTarget.GetCustomAttributes(typeof(FieldConverterAttribute), true);
- if (attribs.Length > 0) {
- var conv = (FieldConverterAttribute) attribs[0];
+ if (attribs.Length > 0)
+ {
+ var conv = (FieldConverterAttribute)attribs[0];
Converter = conv.Converter;
conv.ValidateTypes(FieldInfo);
}
else
- Converter = ConvertHelpers.GetDefaultConverter(FieldFriendlyName ?? fi.Name, FieldType);
+ Converter = ConvertHelpers.GetDefaultConverter(FieldFriendlyName ?? fi.Name,
+ FieldType,
+ defaultCultureName: defaultCultureName);
if (Converter != null)
Converter.mDestinationType = FieldTypeInternal;
- attribs = attibuteTarget.GetCustomAttributes(typeof (FieldNullValueAttribute), true);
+ attribs = attibuteTarget.GetCustomAttributes(typeof(FieldNullValueAttribute), true);
- if (attribs.Length > 0) {
- NullValue = ((FieldNullValueAttribute) attribs[0]).NullValue;
+ if (attribs.Length > 0)
+ {
+ NullValue = ((FieldNullValueAttribute)attribs[0]).NullValue;
- if (NullValue != null) {
- if (!FieldTypeInternal.IsAssignableFrom(NullValue.GetType())) {
+ if (NullValue != null)
+ {
+ if (!FieldTypeInternal.IsAssignableFrom(NullValue.GetType()))
+ {
throw new BadUsageException("The NullValue is of type: " + NullValue.GetType().Name +
" that is not asignable to the field " + FieldInfo.Name +
" of type: " +
@@ -448,7 +480,7 @@ internal FieldBase(FieldInfo fi)
IsNullableType = FieldTypeInternal.IsValueType &&
FieldTypeInternal.IsGenericType &&
- FieldTypeInternal.GetGenericTypeDefinition() == typeof (Nullable<>);
+ FieldTypeInternal.GetGenericTypeDefinition() == typeof(Nullable<>);
}
#endregion
@@ -478,7 +510,8 @@ internal FieldBase(FieldInfo fi)
/// String representation of field
internal string CreateFieldString(object fieldValue)
{
- if (Converter == null) {
+ if (Converter == null)
+ {
if (fieldValue == null)
return string.Empty;
else
@@ -501,9 +534,11 @@ internal object ExtractFieldValue(LineInfo line)
{
//-> extract only what I need
- if (InNewLine) {
+ if (InNewLine)
+ {
// Any trailing characters, terminate
- if (line.EmptyFromPos() == false) {
+ if (line.EmptyFromPos() == false)
+ {
throw new BadUsageException(line,
"Text '" + line.CurrentString +
"' found before the new line of the field: " + FieldInfo.Name +
@@ -512,14 +547,16 @@ internal object ExtractFieldValue(LineInfo line)
line.ReLoad(line.mReader.ReadNextLine());
- if (line.mLineStr == null) {
+ if (line.mLineStr == null)
+ {
throw new BadUsageException(line,
"End of stream found parsing the field " + FieldInfo.Name +
". Please check the class record.");
}
}
- if (IsArray == false) {
+ if (IsArray == false)
+ {
ExtractedInfo info = ExtractFieldString(line);
if (info.mCustomExtractedString == null)
line.mCurrentPos = info.ExtractedTo + 1;
@@ -531,7 +568,8 @@ internal object ExtractFieldValue(LineInfo line)
else
return AssignFromString(info, line).Value;
}
- else {
+ else
+ {
if (ArrayMinLength <= 0)
ArrayMinLength = 0;
@@ -540,14 +578,16 @@ internal object ExtractFieldValue(LineInfo line)
var res = new ArrayList(Math.Max(ArrayMinLength, 10));
while (line.mCurrentPos - CharsToDiscard < line.mLineStr.Length &&
- i < ArrayMaxLength) {
+ i < ArrayMaxLength)
+ {
ExtractedInfo info = ExtractFieldString(line);
if (info.mCustomExtractedString == null)
line.mCurrentPos = info.ExtractedTo + 1;
line.mCurrentPos += CharsToDiscard;
- try {
+ try
+ {
var value = AssignFromString(info, line);
if (value.NullValueUsed &&
@@ -557,16 +597,19 @@ internal object ExtractFieldValue(LineInfo line)
res.Add(value.Value);
}
- catch (NullValueNotFoundException) {
+ catch (NullValueNotFoundException)
+ {
if (i == 0)
break;
else
throw;
}
+
i++;
}
- if (res.Count < ArrayMinLength) {
+ if (res.Count < ArrayMinLength)
+ {
throw new InvalidOperationException(
string.Format(
"Line: {0} Column: {1} Field: {2}. The array has only {3} values, less than the minimum length of {4}",
@@ -576,7 +619,8 @@ internal object ExtractFieldValue(LineInfo line)
res.Count,
ArrayMinLength));
}
- else if (IsLast && line.IsEOL() == false) {
+ else if (IsLast && line.IsEOL() == false)
+ {
throw new InvalidOperationException(
string.Format(
"Line: {0} Column: {1} Field: {2}. The array has more values than the maximum length of {3}",
@@ -613,18 +657,25 @@ private AssignResult AssignFromString(ExtractedInfo fieldString, LineInfo line)
{
var extractedString = fieldString.ExtractedString();
- try {
+ try
+ {
object val;
- if (IsNotEmpty && String.IsNullOrEmpty(extractedString)) {
+ if (IsNotEmpty && String.IsNullOrEmpty(extractedString))
+ {
throw new InvalidOperationException("The value is empty and must be populated.");
- } else if (Converter == null) {
+ }
+ else if (Converter == null)
+ {
if (IsStringField)
val = TrimString(extractedString);
- else {
+ else
+ {
extractedString = extractedString.Trim();
- if (extractedString.Length == 0) {
- return new AssignResult {
+ if (extractedString.Length == 0)
+ {
+ return new AssignResult
+ {
Value = GetNullValue(line),
NullValueUsed = true
};
@@ -633,24 +684,30 @@ private AssignResult AssignFromString(ExtractedInfo fieldString, LineInfo line)
val = Convert.ChangeType(extractedString, FieldTypeInternal, null);
}
}
- else {
+ else
+ {
var trimmedString = extractedString.Trim();
if (Converter.CustomNullHandling == false &&
- trimmedString.Length == 0) {
- return new AssignResult {
+ trimmedString.Length == 0)
+ {
+ return new AssignResult
+ {
Value = GetNullValue(line),
NullValueUsed = true
};
}
- else {
+ else
+ {
if (TrimMode == TrimMode.Both)
val = Converter.StringToField(trimmedString);
else
val = Converter.StringToField(TrimString(extractedString));
- if (val == null) {
- return new AssignResult {
+ if (val == null)
+ {
+ return new AssignResult
+ {
Value = GetNullValue(line),
NullValueUsed = true
};
@@ -658,22 +715,27 @@ private AssignResult AssignFromString(ExtractedInfo fieldString, LineInfo line)
}
}
- return new AssignResult {
+ return new AssignResult
+ {
Value = val
};
}
- catch (ConvertException ex) {
+ catch (ConvertException ex)
+ {
ex.FieldName = FieldInfo.Name;
ex.LineNumber = line.mReader.LineNumber;
ex.ColumnNumber = fieldString.ExtractedFrom + 1;
throw;
}
- catch (BadUsageException) {
+ catch (BadUsageException)
+ {
throw;
}
- catch (Exception ex) {
+ catch (Exception ex)
+ {
if (Converter == null ||
- Converter.GetType().Assembly == typeof (FieldBase).Assembly) {
+ Converter.GetType().Assembly == typeof(FieldBase).Assembly)
+ {
throw new ConvertException(extractedString,
FieldTypeInternal,
FieldInfo.Name,
@@ -682,7 +744,8 @@ private AssignResult AssignFromString(ExtractedInfo fieldString, LineInfo line)
ex.Message,
ex);
}
- else {
+ else
+ {
throw new ConvertException(extractedString,
FieldTypeInternal,
FieldInfo.Name,
@@ -697,7 +760,8 @@ private AssignResult AssignFromString(ExtractedInfo fieldString, LineInfo line)
private String TrimString(string extractedString)
{
- switch (TrimMode) {
+ switch (TrimMode)
+ {
case TrimMode.None:
return extractedString;
@@ -723,8 +787,10 @@ private String TrimString(string extractedString)
/// Null value for object
private object GetNullValue(LineInfo line)
{
- if (NullValue == null) {
- if (FieldTypeInternal.IsValueType) {
+ if (NullValue == null)
+ {
+ if (FieldTypeInternal.IsValueType)
+ {
if (IsNullableType)
return null;
@@ -748,8 +814,10 @@ private object GetNullValue(LineInfo line)
/// null value of discard?
private object GetDiscardedNullValue()
{
- if (NullValue == null) {
- if (FieldTypeInternal.IsValueType) {
+ if (NullValue == null)
+ {
+ if (FieldTypeInternal.IsValueType)
+ {
if (IsNullableType)
return null;
@@ -780,10 +848,13 @@ public object CreateValueForField(object fieldValue)
{
object val;
- if (fieldValue == null) {
- if (NullValue == null) {
+ if (fieldValue == null)
+ {
+ if (NullValue == null)
+ {
if (FieldTypeInternal.IsValueType &&
- Nullable.GetUnderlyingType(FieldTypeInternal) == null) {
+ Nullable.GetUnderlyingType(FieldTypeInternal) == null)
+ {
throw new BadUsageException(
"Null Value found. You must specify a FieldNullValueAttribute in the " + FieldInfo.Name +
" field of type " + FieldTypeInternal.Name + ", because this is a ValueType.");
@@ -796,18 +867,22 @@ public object CreateValueForField(object fieldValue)
}
else if (FieldTypeInternal == fieldValue.GetType())
val = fieldValue;
- else {
+ else
+ {
if (Converter == null)
val = Convert.ChangeType(fieldValue, FieldTypeInternal, null);
- else {
- try {
+ else
+ {
+ try
+ {
if (Nullable.GetUnderlyingType(FieldTypeInternal) != null &&
Nullable.GetUnderlyingType(FieldTypeInternal) == fieldValue.GetType())
val = fieldValue;
else
val = Convert.ChangeType(fieldValue, FieldTypeInternal, null);
}
- catch {
+ catch
+ {
val = Converter.StringToField(fieldValue.ToString());
}
}
@@ -833,9 +908,12 @@ internal void AssignToString(StringBuilder sb, object fieldValue)
if (InNewLine)
sb.Append(StringHelper.NewLine);
- if (IsArray) {
- if (fieldValue == null) {
- if (0 < ArrayMinLength) {
+ if (IsArray)
+ {
+ if (fieldValue == null)
+ {
+ if (0 < ArrayMinLength)
+ {
throw new InvalidOperationException(
string.Format("Field: {0}. The array is null, but the minimum length is {1}",
FieldInfo.Name,
@@ -845,9 +923,10 @@ internal void AssignToString(StringBuilder sb, object fieldValue)
return;
}
- var array = (IList) fieldValue;
+ var array = (IList)fieldValue;
- if (array.Count < ArrayMinLength) {
+ if (array.Count < ArrayMinLength)
+ {
throw new InvalidOperationException(
string.Format("Field: {0}. The array has {1} values, but the minimum length is {2}",
FieldInfo.Name,
@@ -855,7 +934,8 @@ internal void AssignToString(StringBuilder sb, object fieldValue)
ArrayMinLength));
}
- if (array.Count > ArrayMaxLength) {
+ if (array.Count > ArrayMaxLength)
+ {
throw new InvalidOperationException(
string.Format("Field: {0}. The array has {1} values, but the maximum length is {2}",
FieldInfo.Name,
@@ -863,7 +943,8 @@ internal void AssignToString(StringBuilder sb, object fieldValue)
ArrayMaxLength));
}
- for (int i = 0; i < array.Count; i++) {
+ for (int i = 0; i < array.Count; i++)
+ {
object val = array[i];
CreateFieldString(sb, val, IsLast && i == array.Count - 1);
}
diff --git a/FileHelpers/Fields/FixedLengthField.cs b/FileHelpers/Fields/FixedLengthField.cs
index 9312924fc..5b6b73470 100644
--- a/FileHelpers/Fields/FixedLengthField.cs
+++ b/FileHelpers/Fields/FixedLengthField.cs
@@ -42,8 +42,9 @@ private FixedLengthField() {}
/// Field definitions
/// Length of this field
/// Alignment, left or right
- internal FixedLengthField(FieldInfo fi, int length, FieldAlignAttribute align)
- : base(fi)
+ /// Default culture name used for each properties if no converter is specified otherwise. If null, the default decimal separator (".") will be used.
+ internal FixedLengthField(FieldInfo fi, int length, FieldAlignAttribute align, string defaultCultureName=null)
+ : base(fi, defaultCultureName)
{
FixedMode = FixedMode.ExactLength;
Align = new FieldAlignAttribute(AlignMode.Left, ' ');