C# 用户定义的 CSV 映射到 POCO

2023-12-28

我有一个从串行/UDP/TCP 源读取输入数据的系统。输入数据只是不同数据类型(例如 DateTime、double、int、string)的 CSV。示例字符串可能是:

2012/03/23 12:00:00,1.000,23,information,1.234

我目前有(未经测试的)代码,允许用户指定 CSV 列表中的哪个值转到 POCO 的哪个属性。

所以在上面的例子中,我会有一个像这样的对象:

public class InputData
{
 public DateTime Timestamp{get;set;}
 public double Distance{get;set;}
 public int Metres{get;set;}
 public string Description{get;set;}
 public double Height{get;set;}
} 

现在在这个课程中,我有一个方法来解析 CSV 字符串并填充属性。此方法还需要“映射”信息,因为无法保证 CSV 数据将以哪种顺序到达 - 由用户定义正确的顺序。

这是我的映射类:

//This general class handles mapping CSV to objects
public class CSVMapping
{
    //A dictionary holding Property Names (Key) and CSV indexes (Value)
    //0 Based index
    public IDictionary<string, int> Mapping { get; set; }
}

现在我的方法 ParseCSV():

//use reflection to parse the CSV survey input
public bool ParseCSV(string pCSV, CSVMapping pMapping)
{
    if (pMapping == null) return false;
    else
    {
        Type t = this.GetType();
        IList<PropertyInfo> properties = t.GetProperties();
        //Split the CSV values
        string[] values = pCSV.Split(new char[1] { ',' });
        //for each property set its value from the CSV
        foreach (PropertyInfo prop in properties)
        {
            if (pMapping.Mapping.Keys.Contains(prop.Name))
            {
                if (prop.GetType() == typeof(DateTime))
                {
                    if (pMapping.Mapping[prop.Name] >= 0 && pMapping.Mapping[prop.Name] < values.Length)
                    {
                        DateTime tmp;
                        DateTime.TryParse(values[pMapping.Mapping[prop.Name]], out tmp);
                        prop.SetValue(this, tmp, null);
                    }
                }
                else if (prop.GetType() == typeof(short))
                {
                    if (pMapping.Mapping[prop.Name] >= 0 && pMapping.Mapping[prop.Name] < values.Length)
                    {
                        double tmp;
                        double.TryParse(values[pMapping.Mapping[prop.Name]], out tmp);
                        prop.SetValue(this, Convert.ToInt16(tmp), null);
                    }
                }
                else if (prop.GetType() == typeof(double))
                {
                    if (pMapping.Mapping[prop.Name] >= 0 && pMapping.Mapping[prop.Name] < values.Length)
                    {
                        double tmp;
                        double.TryParse(values[pMapping.Mapping[prop.Name]], out tmp);
                        prop.SetValue(this, tmp, null);
                    }
                }
                else if (prop.GetType() == typeof(string))
                {
                    if (pMapping.Mapping[prop.Name] >= 0 && pMapping.Mapping[prop.Name] < values.Length)
                    {
                        prop.SetValue(this, values[pMapping.Mapping[prop.Name]], null);
                    }
                }
            }
        }
        return true;
    }
}

现在我的问题是:

我可能有几个类需要此功能。实现一个泛型类或扩展类来为我进行解析是否有益?我的方法是解析 CSV 数据并填充我的对象的好方法吗?还是有更好的方法来做到这一点?

我已经阅读了有关动态解析 CSV 的其他问题,但所有问题都涉及运行时之前已知的顺序,而我要求用户定义顺序。


OleDB 非常擅长解析 CSV 数据,您不必使用反射。以下是与 OleDB 类映射的主要思想:

  1. 用户定义一个映射(使用委托、流畅的接口或其他东西),它会进入 Mapper 类中的字典。
  2. 解析器创建一个数据表并从映射器插入列
  3. 解析器创建 OleDbConnection、Adapter、Command 并以正确的类型从 CSV 文件填充数据表。
  4. 解析器从 DataTable 中提取 IDataRecords,并且您的 Mapper 需要从 IDataRecord 映射到对象。有关记录到对象映射的指导,我建议阅读 ORM 映射器的源代码,例如 Dapper.NET、Massive、PetaPoco。

OleDb CSV 解析:将 csv 加载到 oleDB 中并强制所有推断的数据类型为字符串 https://stackoverflow.com/questions/1688497/load-csv-into-oledb-and-force-all-inferred-datatypes-to-string

UPDATE

由于只有一个字符串,所以不用说,使用最简单的方法会更好。那么,对于问题:

实现泛型类 - 如果不需要进一步高级解析(不再有字符串,将来不再有约束/功能),我会选择一个接受对象、字符串和映射信息的静态类。它的外观几乎和你现在的一样。这是经过一些修改的版本(可能无法编译,但应该反映总体思路):

public static class CSVParser
{
    public static void FillPOCO(object poco, string csvData, CSVMapping mapping)
    {
        PropertyInfo[] relevantProperties = poco.GetType().GetProperties().Where(x => mapping.Mapping.Keys.Contains(x)).ToArray();
        string[] dataStrings = csvData.Split(',');
        foreach (PropertyInfo property in relevantProperties)
            SetPropertyValue(poco, property, dataStrings[mapping.Mapping[property.Name]]);
    }

    private static void SetPropertyValue(object poco, PropertyInfo property, string value)
    {
        // .. here goes code to change type to the necessary one ..
        property.SetValue(poco, value);
    }
}

关于字符串到类型值的转换 - 有转换.更改类型 http://msdn.microsoft.com/en-us/library/dtb69x08.aspx处理大多数情况的方法。不过,布尔变量有一个特殊的问题(当它给出“0”而不是“false”时)。

至于数据填充 - 虽然据说反射很慢,但对于单个对象和很少使用的情况来说,它应该足够了,因为它很简单。处理 poco 群体问题的常用方法是: 创建运行时转换方法(使用反射进行初始化,然后像任何其他方法一样进行编译和调用) - 通常使用 DynamicMethod、Expression Trees 等实现 - 有很多主题就这样;动态对象的使用(自 C# 4.0 起可用)- 在何处分配/获取变量,无需声明它;使用市场上可用的库(通常来自 ORM 系统,因为它们严重依赖数据到对象的转换)。

就我个人而言,我会衡量反射是否适合我的性能需求,并且会继续解决问题。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C# 用户定义的 CSV 映射到 POCO 的相关文章

随机推荐

  • 删除所有行,从 /pattern/ 之后的两行开始

    假设我有一个文件如下 drink eat XXX pizza blunzn sushi 我想从文件中删除所有行 从模式后的第三行开始XXX 所以结果应该是这样的 drink eat XXX pizza blunzn 删除之后的所有行XXX很
  • Hibernate Criteria n+1 最大结果问题

    使用 hibernate ctiteria 我想选择一个对象及其关联的 oneToMany 对象列表 我想对此列表进行分页 以避免可怕的休眠 n 1 选择问题 这是一个可行的解决方案 需要 10 个父对象对数据库进行 11 次访问 Crit
  • PHP登录系统硬编码用户名和密码

    我必须做一个基本的登录系统来保护页面 并且我无法访问数据库 所以我将用户名和密码硬编码存储在 php 页面中 我的问题是 这个登录系统能抵御攻击吗 我需要它保持大约1个月 任何改进建议都会有所帮助 该代码不在 Laravel 中 即使它看起
  • Nuxt部署错误:服务器资源不可用

    为了在 ssr 模式下部署我们的 nuxt 网站 我们首先在 bitbucket 管道中构建和单元测试网站 如果测试成功 我们将构建文件从 bitbucket 服务器复制到我们的生产服务器并触发启动 问题是 Nuxt 文档没有说明服务器上需
  • 与同时使用 minmax_element 相比 min_element 和 max_element 是否有任何效率优势?

    std minmax element 返回一个对 其中包含一个到最小元素的迭代器作为第一个元素 一个到最大元素的迭代器作为第二个元素 std min element 返回一个迭代器到范围 first last 中的最小元素 std max
  • 如何向我的 Linq 选择添加唯一的行号?

    我有以下代码 public IEnumerable
  • Django 1.5:访问 models.py 中的自定义用户模型字段

    我正在开发 Django 1 5 项目 我有一个自定义用户模型 我们称之为CustomUser 另一个应用程序 SomeApp 需要引用此自定义用户模型 为了ForeignKey等的目的 Django文档说使用 User settings
  • 连接两个字符数组?

    如果我有两个像这样的字符数组 char one 200 char two 200 然后我想做第三个连接这些的我该怎么做呢 我努力了 char three 400 strcpy three one strcat three two 但这似乎不
  • 使用 MultipartEntity 构造 POST 请求

    我想构造一个多部分请求 具有以下参数 名称 字符串 电子邮件 字符串 和文件上传 文件 我正在使用下面的 Java 代码 在 Android 中工作 httppost getRequestLine 打印 POST http www myur
  • Shell 重定向与显式文件处理代码

    我的母语不是英语 所以请原谅这个问题的尴尬标题 我只是不知道如何更好地表达它 我在 FreeBSD 机器上 我有一个用以下语言编写的小过滤工具C它通过读取数据列表stdin并通过输出处理后的列表stdout 我像这样调用它 find typ
  • 为什么微调器中的 onNothingSelected 没有被调用?

    我有一个 Android Spinner 当用户在显示 Spinner 的选择面板时按 后退键 时 我想监听该事件 我已经实现了 OnItemSelectedListener 但按后退键时未调用 onNothingSelected Adap
  • Django 的 mod_wsgi 错误:从守护进程读取响应标头时超时

    我正在运行 Django 2 0 4 和 mod wsgi 4 5 20 当我尝试将站点部署到我们的开发环境时 出现错误 parature 奇怪的是 该站点部署在根目录下VirtualHost正在正常响应 Tue Apr 10 13 34
  • 如何在字段级别创建元注释?

    我有这个带注释的休眠类 Entity public class SimponsFamily Id TableGenerator name ENTITY ID GENERATOR table ENTITY ID GENERATOR TABLE
  • Python有效地找到多个多项式的局部最大值/最小值

    我正在寻找一种有效的方法来查找多个 gt 100万 但独立的四阶多项式的局部最小值给定 指定范围 边界 我有两个要求 R1 即使对于 100 万个不同的多项式方程也有效 R2 局部最小值精确到 0 01 即 2dp 这是我使用创建的一些代码
  • 按计划手动触发 GitHub 操作

    我想按计划手动触发 GitHub 操作 但出现以下代码并出现错误 name Update data on workflow dispatch schedule cron 0 5 30 我正在寻找如何正确执行此操作的解决方案 并且有两种选择
  • 我将如何实现一种简单的基于堆栈的编程语言

    我有兴趣通过实现基于堆栈的编程语言来扩展我的计算机编程知识 我正在寻求从哪里开始的建议 因为我打算让它具有类似 pushint 1 会将值为 1 的整数推送到堆栈顶部 并通过诸如 之类的标签进行流量控制L01 jump L01 到目前为止
  • 我的回收者视图上的问题

    我正在尝试显示 recyclerview 并从 firebase 检索数据 但在添加保存在 firebase 存储上的图像后遇到问题 滚动后关闭 我有另一个 recyclerview 它使用相同的数据库 但没有问题 你能给我解决这个问题吗
  • eclipse插件开发

    我想开发一个eclipse插件 哪一个是最好的开始方式 本教程 http www vogella de articles EclipsePlugIn article html是一个很好的起点 然后 您可以通过阅读一本最新的 Eclipse
  • 如何将 Shell 脚本中的部分字符串提取到变量中

    我正在尝试在 sh 中执行以下操作 这是我的文件 foo bar Tests run 729 Failures 0 Errors 253 Skipped 0 baz 如何将 4 个数字拉入 4 个不同的变量 我现在已经在 sed 和 awk
  • C# 用户定义的 CSV 映射到 POCO

    我有一个从串行 UDP TCP 源读取输入数据的系统 输入数据只是不同数据类型 例如 DateTime double int string 的 CSV 示例字符串可能是 2012 03 23 12 00 00 1 000 23 inform