4

我们有一个需要解析的文件格式,如下所示:

v1|000|sammy|endpoint|blah

这是供应商提供给我们的一种有序的固定宽度格式,因此这 5 个字段中的每一个都映射到类中的特定属性(实际格式大于 30)。

我想通过将序列应用于属性来使用反射来解析它。我可以做到这一点的一种方法是自己编造一些东西 - 编写一个接受单个数字的 Attribute 类,并将该属性应用到具有其序列索引的每个属性,并在 OrderBy 子句中的反射期间查找它。

在 C# 中是否有现有的或更好的方法来执行此操作?例如,是否已经有一个属性?有没有办法在 C# 甚至 MSIL 中询问在类中声明了哪些顺序属性?

4

7 回答 7

4

使用 可以看到属性在元数据中出现的顺序PropertyInfo.MetadataToken。碰巧当前的编译器会使这个顺序与源代码中属性出现的顺序相匹配,因此通过 order by MetadataToken,您将获得与源代码中相同的顺序。

免责声明:未来的编译器可能会改变这一点。如果没有理由,它可能不会,但如果编译器,例如,变成多线程的,可能需要额外的不必要的努力来保持原始顺序。如果您依赖于此,请确保在 .NET Framework 以这种方式更新时出现硬错误而不是静默运行时损坏。

于 2012-07-09T21:22:27.460 回答
1

您使用的是 .net 4.0 吗?这似乎正是创建动态关键字的那种情况。也就是说,似乎顺序和一致性比在任何时间点发生的特定类型更重要,因此您可以通过任何让您满意的规则任意将标题、数据等分配给动态对象,然后将它们拉回使用相同的规则。这也将(大概)允许您不使用反射,这始终是一个优点。

于 2012-07-09T16:28:49.627 回答
1

如果您想使用基于属性的方法,我个人会为此创建一个自定义属性。这不是“标准”操作,因此框架中没有(适当的)属性可用于装饰您的类。

我的方法可能是一个类级别的属性,它接受列表中每个条目的属性名称的字符串数组,或者类似的东西。

话虽如此,我质疑基于属性的方法是否是正确的方法。您可能需要某种类型的管理器类来调解这一点,因为需要做一些“反思”过程。让该类管理此处的关系可能更有意义,尤其是因为它已经需要了解您的类层次结构(以便首先构建类)。

在这一点上,拥有一个可以直接构造对象的自定义类或方法将比尝试使用反射并动态地执行此操作要执行得更好,更易于维护,并且要简单得多。

于 2012-07-09T16:26:25.303 回答
1

我建议使用类似FileHelpers的东西进行解析。

于 2012-07-09T16:39:17.450 回答
1

现在,如果性能不是一个大问题并且您正在使用反射,那么获取没有属性的映射的一种简单方法是使用 RegEx 使用组进行解析。与此实现类似: 从文本文件中读取固定宽度记录

这使用正则表达式,例如:

"^(?<Field1>.{6})(?<Field2>.{16})(?<Field3>.{12})"

由于您可以自己定义组名称,因此您可以明智地选择名称以与您的属性名称完全匹配,这样就可以使用反射自动映射,而无需使用属性。

编辑: 鉴于您最终会在字符串中使用属性名称,这不会非常“重构友好”,我强烈建议对此进行彻底的单元测试,以确保在产生不匹配时重命名您的属性会破坏测试。

于 2012-07-09T16:43:50.223 回答
0

您可以考虑实现类似于Google 的 Protocol Buffers 的东西。

目前没有 C# 实现(我知道),但提供的文档非常好,应该给你一些想法,这些想法比反射慢得多且通常复杂得多。

于 2012-07-09T16:35:55.167 回答
0

这里当然有很多可能的答案,所以这是我遇到的一个马马虎虎的答案:

System.ComponentModel.DataAnnotations 中有一个名为 ColumnAttribute 的现有属性(在 .Net 4.5+ 中,它已移至 System.ComponentModel.DataAnnotations.Schema):

http://msdn.microsoft.com/en-us/library/system.componentmodel.dataannotations.schema.columnattribute(v=vs.110 )

你可以像这样使用它:

[Column(Order=1)]
public string Version { get; set; }

[Column(Order=2)]
public string Id { get; set; }

但是,如果固定宽度格式发生变化,这显然很烦人 - 如果说在开头添加了一个字段,您必须手动进入并更改您输入的 30 多个序数。由于在这种情况下我们不控制格式并且未来的版本可能会频繁出现,因此最好从在类中输入的订单属性中找到具有隐含顺序的内容。

于 2012-07-09T18:59:35.080 回答