diff --git a/CHANGELOG.md b/CHANGELOG.md
index b6cc96d..29fd490 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
+## [1.2.2] - 2024-02-01
+
+- Bugfix in culture handling in DateTimeTypeDecider
+- Add nullability annotations
+
## [1.2.1] - 2024-01-29
- Version bump to resolve symbol package issue on Nuget.org
diff --git a/Directory.Build.props b/Directory.Build.props
new file mode 100644
index 0000000..efd72d5
--- /dev/null
+++ b/Directory.Build.props
@@ -0,0 +1,5 @@
+
+
+ enable
+
+
\ No newline at end of file
diff --git a/SharedAssemblyInfo.cs b/SharedAssemblyInfo.cs
index d6b83d2..1a735e9 100644
--- a/SharedAssemblyInfo.cs
+++ b/SharedAssemblyInfo.cs
@@ -9,6 +9,6 @@
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
-[assembly: AssemblyVersion("1.2.1")]
-[assembly: AssemblyFileVersion("1.2.1")]
-[assembly: AssemblyInformationalVersion("1.2.1")]
+[assembly: AssemblyVersion("1.2.2")]
+[assembly: AssemblyFileVersion("1.2.2")]
+[assembly: AssemblyInformationalVersion("1.2.2")]
diff --git a/Tests/GuesserTests.cs b/Tests/GuesserTests.cs
index 358222f..a6425bd 100644
--- a/Tests/GuesserTests.cs
+++ b/Tests/GuesserTests.cs
@@ -76,12 +76,14 @@ public void Test_OneString_IsType(string guessFor, Type expectedGuess, string cu
: guessFor, Is.EqualTo(expectedParseValue));
}
+#pragma warning disable CA1861
[TestCase("en-us",new []{"5","10"},
typeof(int),2,2,0)]
[TestCase("en-us", new []{"5","10.1"},
typeof(decimal),4,2,1)]
[TestCase("en-us", new []{"5.1","5.000000000"},
typeof(decimal),11,1,1)]
+#pragma warning restore CA1861
public void Test_ManyString_IsType(string culture, string[] guessFor, Type expectedGuess,int expectedStringLength, int expectedBefore,int expectedAfter)
{
var cultureInfo = new CultureInfo(culture);
diff --git a/Tests/PackageListIsCorrectTests.cs b/Tests/PackageListIsCorrectTests.cs
index 53cc67a..16f6e94 100644
--- a/Tests/PackageListIsCorrectTests.cs
+++ b/Tests/PackageListIsCorrectTests.cs
@@ -29,7 +29,7 @@ public sealed partial class PackageListIsCorrectTests
///
///
[TestCase]
- public void TestPackagesDocumentCorrect(string rootPath=null)
+ public void TestPackagesDocumentCorrect(string? rootPath=null)
{
var root= FindRoot(rootPath);
var undocumented = new StringBuilder();
@@ -72,7 +72,7 @@ public void TestPackagesDocumentCorrect(string rootPath=null)
///
///
///
- private static DirectoryInfo FindRoot(string path = null)
+ private static DirectoryInfo FindRoot(string? path = null)
{
if (path != null)
{
diff --git a/Tests/PerformanceTests.cs b/Tests/PerformanceTests.cs
index d9f7b11..6ecff3b 100644
--- a/Tests/PerformanceTests.cs
+++ b/Tests/PerformanceTests.cs
@@ -26,7 +26,8 @@ public void Performance_Decimals()
var decider = new DecimalTypeDecider(new CultureInfo("en-GB"));
- var req = new DatabaseTypeRequest(null);
+ // ReSharper disable once NullableWarningSuppressionIsUsed - this is just for benchmarking
+ var req = new DatabaseTypeRequest(null!);
var sw = new Stopwatch();
diff --git a/TypeGuesser.sln b/TypeGuesser.sln
index 42f7a1d..d22638f 100644
--- a/TypeGuesser.sln
+++ b/TypeGuesser.sln
@@ -10,6 +10,7 @@ EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SolutionItems", "SolutionItems", "{EAE289E1-E8AF-4627-91A6-12E6D5F9F027}"
ProjectSection(SolutionItems) = preProject
CHANGELOG.md = CHANGELOG.md
+ Directory.Build.props = Directory.Build.props
Packages.md = Packages.md
README.md = README.md
SharedAssemblyInfo.cs = SharedAssemblyInfo.cs
diff --git a/TypeGuesser/DatabaseTypeRequest.cs b/TypeGuesser/DatabaseTypeRequest.cs
index 4d4138f..7b5a7c3 100644
--- a/TypeGuesser/DatabaseTypeRequest.cs
+++ b/TypeGuesser/DatabaseTypeRequest.cs
@@ -61,7 +61,7 @@ public int? Width
///
///
public DatabaseTypeRequest(Type cSharpType, int? maxWidthForStrings = null,
- DecimalSize decimalPlacesBeforeAndAfter = null)
+ DecimalSize? decimalPlacesBeforeAndAfter = null)
{
CSharpType = cSharpType;
Width = maxWidthForStrings;
@@ -80,7 +80,7 @@ private bool Equals(DatabaseTypeRequest other)
}
///
- public override bool Equals(object obj)
+ public override bool Equals(object? obj)
{
if (obj is null) return false;
if (ReferenceEquals(this, obj)) return true;
diff --git a/TypeGuesser/Deciders/BoolTypeDecider.cs b/TypeGuesser/Deciders/BoolTypeDecider.cs
index 885834b..6ea10c5 100644
--- a/TypeGuesser/Deciders/BoolTypeDecider.cs
+++ b/TypeGuesser/Deciders/BoolTypeDecider.cs
@@ -21,7 +21,7 @@ protected override IDecideTypesForStrings CloneImpl(CultureInfo newCulture)
}
///
- protected override bool IsAcceptableAsTypeImpl(string candidateString, IDataTypeSize size)
+ protected override bool IsAcceptableAsTypeImpl(string candidateString, IDataTypeSize? size)
{
// "Y" / "N" is boolean unless the settings say it can't
if (!Settings.CharCanBeBoolean && SingleCharacter.IsMatch(candidateString))
diff --git a/TypeGuesser/Deciders/DateTimeTypeDecider.cs b/TypeGuesser/Deciders/DateTimeTypeDecider.cs
index c8d93de..479b85c 100644
--- a/TypeGuesser/Deciders/DateTimeTypeDecider.cs
+++ b/TypeGuesser/Deciders/DateTimeTypeDecider.cs
@@ -32,8 +32,11 @@ public class DateTimeTypeDecider(CultureInfo cultureInfo) : DecideTypesForString
///
public static readonly string[] TimeFormats;
- private string[] _dateFormatToUse;
- private CultureInfo _culture;
+ private string[] _dateFormatToUse =
+ cultureInfo.DateTimeFormat.ShortDatePattern.IndexOf('M') > cultureInfo.DateTimeFormat.ShortDatePattern.IndexOf('d')
+ ? DateFormatsDM
+ : DateFormatsMD;
+ private CultureInfo _culture=cultureInfo;
///
/// Setting this to false will prevent changing the e.g. when
@@ -49,10 +52,7 @@ public class DateTimeTypeDecider(CultureInfo cultureInfo) : DecideTypesForString
public override CultureInfo Culture { get => _culture;
set
{
- value ??= CultureInfo.CurrentCulture;
-
_dateFormatToUse = value.DateTimeFormat.ShortDatePattern.IndexOf('M') > value.DateTimeFormat.ShortDatePattern.IndexOf('d') ? DateFormatsDM : DateFormatsMD;
-
_culture = value;
} }
@@ -196,13 +196,13 @@ public void GuessDateFormat(IEnumerable samples)
}
///
- public override bool IsAcceptableAsType(string candidateString, IDataTypeSize size)
+ public override bool IsAcceptableAsType(string candidateString, IDataTypeSize? size)
{
return IsExplicitDate(candidateString) || base.IsAcceptableAsType(candidateString, size);
}
///
- protected override bool IsAcceptableAsTypeImpl(string candidateString, IDataTypeSize sizeRecord)
+ protected override bool IsAcceptableAsTypeImpl(string candidateString, IDataTypeSize? sizeRecord)
{
//if it's a float then it isn't a date is it! thanks C# for thinking 1.1 is the first of January
if (_decimalChecker.IsAcceptableAsType(candidateString, sizeRecord))
diff --git a/TypeGuesser/Deciders/DecideTypesForStrings.cs b/TypeGuesser/Deciders/DecideTypesForStrings.cs
index 664b841..6a55fa5 100644
--- a/TypeGuesser/Deciders/DecideTypesForStrings.cs
+++ b/TypeGuesser/Deciders/DecideTypesForStrings.cs
@@ -50,7 +50,7 @@ protected DecideTypesForStrings(CultureInfo culture, TypeCompatibilityGroup comp
}
///
- public virtual bool IsAcceptableAsType(string candidateString,IDataTypeSize size)
+ public virtual bool IsAcceptableAsType(string candidateString,IDataTypeSize? size)
{
//we must preserve leading zeroes if it's not actually 0 -- if they have 010101 then we have to use string but if they have just 0 we can use decimal
return !IDecideTypesForStrings.ZeroPrefixedNumber.IsMatch(candidateString) && IsAcceptableAsTypeImpl(candidateString, size);
@@ -71,7 +71,7 @@ protected bool IsExplicitDate(string candidateString)
}
///
- public object Parse(string value)
+ public object? Parse(string value)
{
if (string.IsNullOrWhiteSpace(value))
return null;
@@ -105,7 +105,7 @@ public IDecideTypesForStrings Clone()
///
///
///
- protected virtual object ParseImpl(string value)
+ protected virtual object? ParseImpl(string value)
{
return value.To(Culture);
}
@@ -116,7 +116,7 @@ protected virtual object ParseImpl(string value)
///
///
///
- protected virtual bool IsAcceptableAsTypeImpl(string candidateString,IDataTypeSize size)
+ protected virtual bool IsAcceptableAsTypeImpl(string candidateString,IDataTypeSize? size)
{
return candidateString.IsConvertibleTo(Culture);
}
diff --git a/TypeGuesser/Deciders/DecimalTypeDecider.cs b/TypeGuesser/Deciders/DecimalTypeDecider.cs
index f30b428..59649f7 100644
--- a/TypeGuesser/Deciders/DecimalTypeDecider.cs
+++ b/TypeGuesser/Deciders/DecimalTypeDecider.cs
@@ -30,7 +30,7 @@ protected override IDecideTypesForStrings CloneImpl(CultureInfo culture)
}
///
- protected override bool IsAcceptableAsTypeImpl(string candidateString,IDataTypeSize sizeRecord)
+ protected override bool IsAcceptableAsTypeImpl(string candidateString,IDataTypeSize? sizeRecord)
{
candidateString = TrimTrailingZeros(candidateString);
@@ -41,7 +41,7 @@ protected override bool IsAcceptableAsTypeImpl(string candidateString,IDataTypeS
return false;
var dec = (SqlDecimal) t;
- sizeRecord.Size.IncreaseTo(dec.Precision - dec.Scale,dec.Scale);
+ sizeRecord?.Size.IncreaseTo(dec.Precision - dec.Scale,dec.Scale);
return true;
}
diff --git a/TypeGuesser/Deciders/IDecideTypesForStrings.cs b/TypeGuesser/Deciders/IDecideTypesForStrings.cs
index 3219bad..8ca1aa1 100644
--- a/TypeGuesser/Deciders/IDecideTypesForStrings.cs
+++ b/TypeGuesser/Deciders/IDecideTypesForStrings.cs
@@ -56,14 +56,14 @@ public partial interface IDecideTypesForStrings
/// The current size estimate of floating point numbers (or null if not appropriate). This will be modified by the method
/// if appropriate to the data passed
/// True if the is a valid value for the by the decider
- bool IsAcceptableAsType(string candidateString,IDataTypeSize size);
+ bool IsAcceptableAsType(string candidateString,IDataTypeSize? size);
///
/// Converts the provided to an object of the Type modelled by this .
///
///
///
- object Parse(string value);
+ object? Parse(string value);
///
/// Returns a new instance of this class with the same and etc
diff --git a/TypeGuesser/Deciders/IntTypeDecider.cs b/TypeGuesser/Deciders/IntTypeDecider.cs
index bc7d1ab..795f42c 100644
--- a/TypeGuesser/Deciders/IntTypeDecider.cs
+++ b/TypeGuesser/Deciders/IntTypeDecider.cs
@@ -20,7 +20,7 @@ protected override IDecideTypesForStrings CloneImpl(CultureInfo newCulture)
}
///
- protected override bool IsAcceptableAsTypeImpl(string candidateString, IDataTypeSize sizeRecord)
+ protected override bool IsAcceptableAsTypeImpl(string candidateString, IDataTypeSize? sizeRecord)
{
if(IsExplicitDate(candidateString))
return false;
@@ -28,7 +28,7 @@ protected override bool IsAcceptableAsTypeImpl(string candidateString, IDataType
if (!candidateString.IsConvertibleTo(out int i, Culture))
return false;
- sizeRecord.Size.IncreaseTo(i.ToString().Trim('-').Length,0);
+ sizeRecord?.Size.IncreaseTo(i.ToString().Trim('-').Length,0);
return true;
}
}
\ No newline at end of file
diff --git a/TypeGuesser/Deciders/NeverGuessedTypeDecider.cs b/TypeGuesser/Deciders/NeverGuessedTypeDecider.cs
index eca8d2e..5681574 100644
--- a/TypeGuesser/Deciders/NeverGuessedTypeDecider.cs
+++ b/TypeGuesser/Deciders/NeverGuessedTypeDecider.cs
@@ -20,7 +20,7 @@ public sealed class NeverGuessTheseTypeDecider(CultureInfo culture) : DecideType
protected override object ParseImpl(string value) => throw new NotSupportedException();
///
- protected override bool IsAcceptableAsTypeImpl(string candidateString, IDataTypeSize sizeRecord) =>
+ protected override bool IsAcceptableAsTypeImpl(string candidateString, IDataTypeSize? sizeRecord) =>
//strings should never be interpreted as byte arrays
false;
}
\ No newline at end of file
diff --git a/TypeGuesser/Deciders/TimeSpanTypeDecider.cs b/TypeGuesser/Deciders/TimeSpanTypeDecider.cs
index fc3fe92..e2580d9 100644
--- a/TypeGuesser/Deciders/TimeSpanTypeDecider.cs
+++ b/TypeGuesser/Deciders/TimeSpanTypeDecider.cs
@@ -20,7 +20,7 @@ public sealed class TimeSpanTypeDecider(CultureInfo culture) : DecideTypesForStr
protected override object ParseImpl(string value) => DateTime.Parse(value).TimeOfDay;
///
- protected override bool IsAcceptableAsTypeImpl(string candidateString,IDataTypeSize sizeRecord)
+ protected override bool IsAcceptableAsTypeImpl(string candidateString,IDataTypeSize? sizeRecord)
{
try
{
diff --git a/TypeGuesser/DecimalSize.cs b/TypeGuesser/DecimalSize.cs
index 75a71a0..e3ca99a 100644
--- a/TypeGuesser/DecimalSize.cs
+++ b/TypeGuesser/DecimalSize.cs
@@ -136,7 +136,7 @@ private bool Equals(DecimalSize other)
}
///
- public override bool Equals(object obj)
+ public override bool Equals(object? obj)
{
if (obj is null) return false;
if (ReferenceEquals(this, obj)) return true;
diff --git a/TypeGuesser/GuessSettings.cs b/TypeGuesser/GuessSettings.cs
index 2f31da0..5e00892 100644
--- a/TypeGuesser/GuessSettings.cs
+++ b/TypeGuesser/GuessSettings.cs
@@ -15,7 +15,7 @@ public class GuessSettings
///
/// Optional, when set dates must be in one of these formats and any string in this format will be picked as a date.
///
- public string[] ExplicitDateFormats { get; set; }
+ public string[] ExplicitDateFormats { get; set; } = [];
///
diff --git a/TypeGuesser/Guesser.cs b/TypeGuesser/Guesser.cs
index eb673af..21ed4d1 100644
--- a/TypeGuesser/Guesser.cs
+++ b/TypeGuesser/Guesser.cs
@@ -119,7 +119,7 @@ public void AdjustToCompensateForValues(IEnumerable
/// Thrown if you mix strings with hard Typed objects when supplying
///
- public void AdjustToCompensateForValue(object o)
+ public void AdjustToCompensateForValue(object? o)
{
while (true)
{
@@ -136,7 +136,7 @@ public void AdjustToCompensateForValue(object o)
var oToString = o.ToString();
//we might need to fallback on a string later on, in this case we should always record the maximum length of input seen before even if it is acceptable as int, double, dates etc
- Guess.Width = Math.Max(Guess.Width ?? -1, GetStringLength(oToString));
+ Guess.Width = Math.Max(Guess.Width ?? -1, GetStringLength(oToString??string.Empty));
//if it's a string
if (o is string oAsString)
@@ -179,7 +179,7 @@ public void AdjustToCompensateForValue(object o)
}
//if we have a decider for this lets get it to tell us the decimal places (if any)
- if (_typeDeciders.Dictionary.TryGetValue(o.GetType(),out var decider))
+ if (oToString!=null && _typeDeciders.Dictionary.TryGetValue(o.GetType(),out var decider))
decider.IsAcceptableAsType(oToString, Guess);
break;
}
@@ -265,7 +265,7 @@ private void ThrowIfNotSupported(Type currentEstimate)
///
/// If the current does not have a parser defined
///
- public object Parse(string val)
+ public object? Parse(string val)
{
if (Guess.CSharpType == typeof(string))
return val;