“ N / A”作为int字段的空值

时间:2019-03-21 01:51:21

标签: c# csvhelper

我必须处理(即无法控制)csv文件,其中“ N / A”是“应该”为整数的字段的可能值,并且我一直在尝试找出如何“滚动我的”自己的” TypeConversion类来处理此问题,但未能找到示例。 Josh的示例页面在该特定领域非常缺乏,而我能够找到的最接近的stackoverflow问题是2013年的this one

然后,我找到了对NullValuesAttribute的引用,这似乎正是我所需要的,但是后来却不知道如何使用它。 VisualStudio的Intellisense也无济于事。 :)

理想情况下,我希望将“ N / A”转换为0(零)。有人可以帮忙吗?

在人们告诉我“好吧,很明显...”之前,我应该说这是我的第一个C#程序(除了教程,从字面上看),而且还有一个时间因素-否则我会很高兴地在我的探索中自己的。

[更新:在CsvHelper Parsing boolean from String尝试了最佳适应解决方案]

因此,以上述问题的解决方案为起点,我这样做了:

static void Main()
{
    var rows = new List<Job>();

    using (var reader = new StreamReader("mydatafile.csv")
    using (var csv = new CsvReader(reader))
    {
         csv.Configuration.RegisterClassMap<JobMap>();
         while (csv.Read())
         {
              var record = new Job
              {
                   JobId = csv.GetField<int>("Job ID"),
                   ItemCount = csv.GetField<int>("Item Count")
              };
              rows.Add(record);
         }
    }
}

public class Job
{
    public int JobId { get; set; }
    public int ItemCount { get; set; }
}

public sealed class JobMap : ClassMap<Job>
{
    Map(m => m.JobId);
    Map(m => m.ItemCount).TypeConverterOption.NullValues("N/A");
}

我的想法是,指定NullValues将使TypeConverter将“ N / A”转换为null(因为似乎不存在与“ BooleanValues”方法等效的Int32。

不幸的是,这仍然引发了异常:

CsvHelper.TypeConversion.TypeConverterException: 'The conversion cannot be performed.
Text: 'N/A'
MemberType: 
TypeConverter: 'CsvHelper.TypeConversion.Int32Converter''

因此,看起来我将不得不扩展Int32Converter。是吗?

2 个答案:

答案 0 :(得分:1)

您可以像这样定义自定义类型转换器:

using CsvHelper;
using CsvHelper.TypeConversion;
using CsvHelper.Configuration;

public class CustomInt32Converter: Int32Converter {
    public override object ConvertFromString(string text, IReaderRow row, MemberMapData memberMapData)
    {
        if (text == "N/A") return 0;
        return base.ConvertFromString(text, row, memberMapData);
    }
}

然后您可以在此行中注册转换器:

csv.Configuration.TypeConverterCache.AddConverter<int>(new CustomInt32Converter());

答案 1 :(得分:0)

虽然不是最优雅的解决方案,但至少目前对我而言有效:

从上面的代码中,删除csv.Configuration...类。也不需要static int HandleNA (CsvReader csv, string field) { return (csv.GetField<string>(field) == "N/A") ? 0 : csv.GetField<int>(field); } 行。

创建新功能

var record = new Job
{
    JobId = csv.GetField<int>("Job ID"),
    ItemCount = HandleNA(csv, "Item Count")
};

并在

中使用它
static int Main(string[] args)
{
    try
    {
        string destinationServer = args[0];
        string destinationDatabase = args[1];
        string userID = args[2];
        string password = args[3];
        string publishFileFullPath = args[4];
        string dacpacFileFullPath = args[5];

        SetupRegistryQueryExecutionTimeout();
        PublishDacpacSimple(destinationServer, destinationDatabase, userID, password, publishFileFullPath, dacpacFileFullPath);

        return 0; //where 0 = success
    }
    catch (Exception ex)
    {
        Console.WriteLine("Error in Main: " + ex.Message + "\n" + ex.StackTrace);

        for (int i = 0; i < args.Length; i++)
        {
            Console.WriteLine("Value in args[" + i + "]: " + (i == 3 ? "**********" : args[i]));
        }

        Console.WriteLine("Failed to publish dacpac.");

        //Return error state
        return 1;
    }
}

private static void SetupRegistryQueryExecutionTimeout()
{
    //Fixes an annoying issue with slow sql servers: https://stackoverflow.com/a/26108419/2912011
    RegistryKey myKey = Registry.CurrentUser.OpenSubKey("Software\\Microsoft\\VisualStudio\\12.0\\SQLDB\\Database", true);
    if (myKey != null)
    {
        myKey.SetValue("QueryTimeoutSeconds", "0", RegistryValueKind.DWord);
        myKey.Close();
    }

    myKey = Registry.CurrentUser.OpenSubKey("Software\\Microsoft\\VisualStudio\\14.0\\SQLDB\\Database", true);
    if (myKey != null)
    {
        myKey.SetValue("QueryTimeoutSeconds", "0", RegistryValueKind.DWord);
        myKey.Close();
    }

    myKey = Registry.CurrentUser.OpenSubKey("Software\\Microsoft\\VisualStudio\\15.0\\SQLDB\\Database", true);
    if (myKey != null)
    {
        myKey.SetValue("QueryTimeoutSeconds", "0", RegistryValueKind.DWord);
        myKey.Close();
    }
}

private static void PublishDacpacSimple(string destinationServer, 
    string destinationDatabase, 
    string userID, 
    string password, 
    string publishFileFullPath, 
    string dacpacFileFullPath)
{
    string connectionString = BuildConnectionString(destinationServer, destinationDatabase, userID, password);

    XmlDocument xdoc = new XmlDocument();

    xdoc.Load(publishFileFullPath);

    DacServices ds = new DacServices(connectionString);
    using (DacPackage package = DacPackage.Load(dacpacFileFullPath))
    {
        var options = new DacDeployOptions();                

        options.CommandTimeout = 600;              

        ds.Message += (object sender, DacMessageEventArgs eventArgs) => Console.WriteLine(eventArgs.Message.Message);

        ds.Deploy(package, destinationDatabase, true, options);
    }
}