[TestCase("5,000", typeof(int), "de-de", 5, 1, 0, 5)] //germans swap commas and dots public void Test_OneString_IsType(string guessFor, Type expectedGuess, string culture, int expectedStringLength, int expectedBefore, int expectedAfter, object expectedParseValue) { var cultureInfo = new CultureInfo(culture); var guesser = new Guesser() { Culture = cultureInfo }; guesser.AdjustToCompensateForValue(guessFor); Assert.AreEqual(expectedGuess, guesser.Guess.CSharpType, "Guessed Type did not match"); Assert.AreEqual(expectedStringLength, guesser.Guess.Width, "String length guessed didn't match"); Assert.AreEqual(expectedBefore, guesser.Guess.Size.NumbersBeforeDecimalPlace, "BeforeDecimalPlace didn't match"); Assert.AreEqual(expectedAfter, guesser.Guess.Size.NumbersAfterDecimalPlace, "AfterDecimalPlace didn't match"); TypeDeciderFactory factory = new TypeDeciderFactory(cultureInfo); if (factory.IsSupported(guesser.Guess.CSharpType)) { Assert.AreEqual(expectedParseValue, factory.Create(guesser.Guess.CSharpType).Parse(guessFor)); } else { Assert.AreEqual(expectedParseValue, guessFor); } }
/// <summary> /// Replaces all string representations for data types that can be problematic/ambiguous (e.g. DateTime or TimeSpan) /// into hard typed objects using appropriate decider e.g. <see cref="DateTimeDecider"/>. /// </summary> /// <param name="dt"></param> protected void ConvertStringTypesToHardTypes(DataTable dt) { var dict = GetMapping(dt.Columns.Cast <DataColumn>(), out _); var factory = new TypeDeciderFactory(Culture); //These are the problematic Types Dictionary <Type, IDecideTypesForStrings> deciders = factory.Dictionary; //for each column in the destination foreach (var kvp in dict) { //if the destination column is a problematic type var dataType = kvp.Value.DataType.GetCSharpDataType(); if (deciders.ContainsKey(dataType)) { //if it's already not a string then that's fine (hopefully its a legit Type e.g. DateTime!) if (kvp.Key.DataType != typeof(string)) { continue; } //create a new column hard typed to DateTime var newColumn = dt.Columns.Add(kvp.Key.ColumnName + "_" + Guid.NewGuid().ToString(), dataType); var decider = deciders[dataType]; //if it's a DateTime decider then guess DateTime culture based on values in the table if (decider is DateTimeTypeDecider dtDecider) { dtDecider.GuessDateFormat(dt.Rows.Cast <DataRow>().Take(500).Select(r => r[kvp.Key] as string)); } foreach (DataRow dr in dt.Rows) { //parse the value dr[newColumn] = decider.Parse(dr[kvp.Key] as string) ?? DBNull.Value; } //if the DataColumn is part of the Primary Key of the DataTable (in memory) //then we need to update the primary key to include the new column not the old one if (dt.PrimaryKey != null && dt.PrimaryKey.Contains(kvp.Key)) { dt.PrimaryKey = dt.PrimaryKey.Except(new [] { kvp.Key }).Union(new [] { newColumn }).ToArray(); } var oldOrdinal = kvp.Key.Ordinal; //drop the original column dt.Columns.Remove(kvp.Key); //rename the hard typed column to match the old column name newColumn.ColumnName = kvp.Key.ColumnName; if (oldOrdinal != -1) { newColumn.SetOrdinal(oldOrdinal); } } } }
public void BigInt_TypeDeciderFactory() { var factory = new TypeDeciderFactory(new CultureInfo("en-US")); // The IDecideTypesForStrings for long should be DecimalTypeDecider Assert.IsTrue(factory.Dictionary[typeof(Int64)] is DecimalTypeDecider); Assert.IsTrue(factory.Dictionary[typeof(long)] is DecimalTypeDecider); }
public DataTable StronglyTypeTable(DataTable workingTable, ExplicitTypingCollection explicitTypingCollection) { Dictionary <int, IDecideTypesForStrings> deciders = new Dictionary <int, IDecideTypesForStrings>(); var factory = new TypeDeciderFactory(_culture); if (!string.IsNullOrWhiteSpace(_explicitDateTimeFormat)) { factory.Settings.ExplicitDateFormats = new [] { _explicitDateTimeFormat } } ; DataTable dtCloned = workingTable.Clone(); bool typeChangeNeeded = false; foreach (DataColumn col in workingTable.Columns) { //if we have already handled it if (explicitTypingCollection != null && explicitTypingCollection.ExplicitTypesCSharp.ContainsKey(col.ColumnName)) { continue; } //let's make a decision about the data type to use based on the contents var computedType = new Guesser(); computedType.AdjustToCompensateForValues(col); //Type based on the contents of the column if (computedType.ShouldDowngradeColumnTypeToMatchCurrentEstimate(col)) { dtCloned.Columns[col.ColumnName].DataType = computedType.Guess.CSharpType; //if we have a type decider to parse this data type if (factory.IsSupported(computedType.Guess.CSharpType)) { deciders.Add(col.Ordinal, factory.Create(computedType.Guess.CSharpType)); //record column index and parser } typeChangeNeeded = true; } } if (typeChangeNeeded) { foreach (DataRow row in workingTable.Rows) { dtCloned.Rows.Add(row.ItemArray.Select((v, idx) => deciders.ContainsKey(idx) && v is string s? deciders[idx].Parse(s) : v).ToArray()); } return(dtCloned); } return(workingTable); }
public FlatFileToDataTablePusher(FlatFileToLoad fileToLoad, FlatFileColumnCollection headers, Func <string, object> hackValuesFunc, bool attemptToResolveNewlinesInRecords, CultureInfo culture) { _fileToLoad = fileToLoad; _headers = headers; _hackValuesFunc = hackValuesFunc; _attemptToResolveNewlinesInRecords = attemptToResolveNewlinesInRecords; _culture = culture ?? CultureInfo.CurrentCulture; typeDeciderFactory = new TypeDeciderFactory(_culture); }
public FlatFileToDataTablePusher(FlatFileToLoad fileToLoad, FlatFileColumnCollection headers, Func <string, object> hackValuesFunc, bool attemptToResolveNewlinesInRecords, CultureInfo culture, string explicitDateTimeFormat) { _fileToLoad = fileToLoad; _headers = headers; _hackValuesFunc = hackValuesFunc; _attemptToResolveNewlinesInRecords = attemptToResolveNewlinesInRecords; _culture = culture ?? CultureInfo.CurrentCulture; _explicitDateTimeFormat = explicitDateTimeFormat; typeDeciderFactory = new TypeDeciderFactory(_culture); if (!string.IsNullOrWhiteSpace(explicitDateTimeFormat)) { typeDeciderFactory.Settings.ExplicitDateFormats = new [] { explicitDateTimeFormat } } ; }
public void Guess_TF_Factory() { var candidate = "T"; //default is true Assert.IsTrue(GuessSettingsFactory.Defaults.CharCanBeBoolean); var factory = new TypeDeciderFactory(CultureInfo.CurrentCulture); var deciderOld = factory.Create(typeof(bool)); //T = True Assert.IsTrue(deciderOld.IsAcceptableAsType(candidate, null)); Assert.IsTrue(deciderOld.IsAcceptableAsType("1", null)); factory.Settings.CharCanBeBoolean = false; var deciderNew = factory.Create(typeof(bool)); Assert.IsFalse(deciderOld == deciderNew, "Factory Create created a reference to the same old instance! not a fresh one"); Assert.IsTrue(deciderOld.Settings.CharCanBeBoolean); Assert.IsFalse(deciderNew.Settings.CharCanBeBoolean); Assert.IsFalse(deciderNew.IsAcceptableAsType(candidate, null)); Assert.IsTrue(deciderNew.IsAcceptableAsType("1", null)); //setting does not affect 1/0 }
public ParseStringsUpdater(CultureInfo culture) { _factory = new(culture); }