【问题标题】:How to get differing value type out of an concrete implementation if only Interface / abstract class is known?如果只知道接口/抽象类,如何从具体实现中获取不同的值类型?
【发布时间】:2011-07-05 16:27:07
【问题描述】:

我正在使用什么:
VB.NET、NET 3.5、OpenXML SDK 2.0

我想做的事:
我正在为我的应用程序创建一个 xlsx 读取器/写入器(基于 OpenXML SDK 2.0)。我想读取 xlsx 文件并将每行中包含的数据存储在 DTO/PONO 中。此外,我想读取 xlsx 文件,然后对其进行修改并保存。

我的想法:
现在我的问题不在于 OpenXML SDK,我可以做我需要做的。

我的问题是如何构建我的组件。具体来说,我在电子表格的最低级别(单元格)存在多态性问题。

Excel/OpenXML 中的单元格可以关联不同类型的数据。如时间、日期、数字、文本或公式。在从电子表格读取/写入电子表格时,需要以不同的方式处理这些不同的类型。

我决定为所有子类型(如 TextCell、NumberCell、DateCell 等)提供一个通用接口。

现在,当我从电子表格中读取单元格时,方法/工厂可以决定创建哪种类型的单元格。

现在因为单元格是实际实现的抽象,所以它不知道/不需要知道它是什么类型。为了编写/修改单元格,我通过在要保留的单元格上调用 .write(ICellWriter) 来解决此问题。由于单元本身知道它包含什么类型的数据,它知道它需要调用 ICellWriter 的哪个方法(静态多态性)。

我的问题:
写入 xlsx 文件没有问题。我的问题是,如何在不使用类型检查的情况下将数据从单元格中取出到 DTO/PONO 中 -> If TypeOf variable is ClassX then doesomething End If。由于方法/属性必须具有不同的签名,并且不允许仅使用不同的返回类型进行区分。

编辑:

对象(指单元格)的持有者(集合,在这种情况下是表格/电子表格的一行)不知道具体的实现。因此,对于编写单元格,我将其传递给 Cellwriter。此 Cellwriter 具有重载方法,例如 Write(num as Integer)Write(text as String)Write(datum as Date)。将这个传递给它的单元格对象然后使用它所拥有的数据类型调用Write() 方法。这是可行的,因为没有返回值被传回。

但是当我需要返回具体的数据类型时该怎么办?

有什么想法、建议、见解?

谢谢

编辑:
词汇表:

  • DTO:数据传输对象
  • PONO:普通旧 .Net 对象
  • xlsx:指excel工作簿文件的文件结尾

编辑:
Cell“子类型”实现了一个通用接口,而不是从一个通用超类继承。

编辑:
在考虑了这个问题之后,我开始意识到,如果不反思或不知道我期待什么类型的细胞,这是不可能的。基本上,我试图重新创建一个电子表格或具有类似功能的东西,而且对于我的需要来说太抽象/可配置了。感谢您花费时间和精力来写答案。我接受了最接近我意识到的答案。

【问题讨论】:

  • 我在问题的末尾添加了一个词汇表,希望对您有所帮助。
  • 我知道这并不能直接回答问题,但您为什么不直接使用 ado.net 读取 excel 文件?有什么特殊情况你不能这样做吗?
  • @Dom:也许 ado.net 可能是一个选择 :)。您可以使用 ado.net 修改“命名范围”的引用吗?我认为 ado.net 将在您将新行插入工作表时使用正确的格式。
  • 我使用了一个将 writer 作为第一个参数的扩展方法。然后我简单地为每种可能进入的数据类型创建了一个函数。 {Decimal, Double, and Float} 称为公共私有 WriteCell;串另一个;依此类推,日期时间等等。然后我对枚举使用了通用的 public WriteCell(Of T As Structure, IConvertable, ...) 。最通用的是 WriteCell(writer, obj As Object, rowIndex, columnIndex, Optional styleIndex As Integer = 0),它将转换为相应的类型。然后 ExportDataTableToSpreadsheet,将每个单元格写入该 Object WriteCell
  • 另一个想法是使用 T4 模板(免费)或其他代码生成工具。这将为您提供类似 C++ 的模板而不是泛型。这可以绕过我必须经历的所有打字(vs2010 有更好的支持)。

标签: vb.net oop .net-3.5 polymorphism


【解决方案1】:

我不认为你可以。

如果我理解正确,您有不同类型的单元格(StringCell、IntCell),并且每个具体类都返回一个“Object”类型的对象。当您使用基类“Cell”并获取它的值时 - 它是 Object 类型。

要将其用作字符串、整数、日期等...等等...我认为您需要以一种或另一种方式检查该对象的类型。您可以像演示的那样使用 TypeOf ;我还在基类上看到了类似“.GetValueAsString()/.GetValueAsInteger()”的东西。但是你仍然需要足够的知识来说'Dim myInt as Integer = myCell.GetValueAsInteger()'

一般来说,至少如果您订阅了 SOLID 主体,则不必在意。

它指出,在计算机程序中,如果 S 是 T 的子类型,则类型 T 的对象可以用类型 S 的对象替换(即,类型 S 的对象可以替换类型 T 的对象),无需更改该程序的任何理想属性(正确性、执行的任务等)

http://en.wikipedia.org/wiki/Liskov_substitution_principle

如果您有单元格的子类型,但不能互换使用它们,则最好不要使用继承。

我不知道您打算如何处理单元格中的值,这些值需要您拥有具体类而不是使用基类;但是有可能在基础本身中公开该功能。 IE - 如果您需要添加两个单元格,您可以在不知道它们是什么子类型的情况下将它们视为通用单元格(也许。至少假设它们是兼容类型)。无论如何,您应该能够在 DTO 中返回基类。

至少,我是这样理解的。在听我讲话之前,我当然会等待更多的人加入。

【讨论】:

  • 在这种情况下。制作一个可以保存所有内容直到最后处理的对象是最好的方法。因为他使用的是 SAX,它将 xml blobx 写入 zip 文件(在幕后);自定义类对象非常擅长一次序列化;而且xml和OO是一对一的关系,继承是个不错的选择。由于xml和OO关系密切,SOLID/composition我就不费心了。
猜你喜欢
  • 2012-06-17
  • 2011-12-23
  • 1970-01-01
  • 2020-10-20
  • 1970-01-01
  • 2021-04-09
  • 2023-03-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多