2

我需要创建一个通用解决方案来创建从 xsd 生成的类的实例。例如:

<?xml version="1.0" encoding="utf-8"?>
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="PS">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="P" maxOccurs="unbounded">
          <xs:complexType>
            <xs:sequence>
              <xs:element name="FXs" maxOccurs="1" minOccurs="0">
                <xs:complexType>
                  <xs:sequence>
                    <xs:element maxOccurs="unbounded" name="FX" minOccurs="1">
                      <xs:complexType>
                        <xs:attribute name="asOfDate" type="xs:date" use="required" />
                        <xs:attribute name="currency" type="xs:string" use="required" />
                        <xs:attribute name="rate" type="xs:decimal" use="required" />
                      </xs:complexType>
                    </xs:element>
                  </xs:sequence>
                </xs:complexType>
              </xs:element>
 </xs:sequence>
            <xs:attribute name="PName" type="xs:string" />
            <xs:attribute name="currency" type="xs:string" />
          </xs:complexType>
        </xs:element>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>

当我从这个 xsd 运行时生成程序集时,它将具有 PS、PSP 和 PSFX 类。在这种情况下,我知道属性和期望的内容,因此 createinstance 和 getproperties 和 setvalue 将起作用。我知道投资组合将有一系列 PortfoliosPortfolio。

case "PS":
                                    if (p== null)
                                        p= myAssembly.CreateInstance(cls.FullName);
                                    break;

                                case "PSP":
                                    myClass = myAssembly.CreateInstance(cls.FullName);
                                    myClass.GetType().GetProperty("PName").SetValue(myClass, dt.Rows[0]["PortfolioName"].ToString(), null);
                                    myClass.GetType().GetProperty("currency").SetValue(myClass, dt.Rows[0]["Currency"].ToString(), null);
                                    if (myClasses == null)
                                        myClasses = Array.CreateInstance(myClass.GetType(), deals.Count());
                                    myClasses.SetValue(myClass, l);
                                    l++;
                                    portfolio.GetType().GetProperty("P").SetValue(p, myClasses, null);

现在我想要一个通用的解决方案,它可以采用任何 xsd(不仅仅是上面的)并生成一个程序集。我已经生成了汇编,但现在我的问题是如何为不知道其中存在哪些属性的类动态分配属性?我的意思是我如何知道一个类在创建通用解决方案时正在使用另一个类的对象列表。因此,有一种方法可以获取实例和属性,而不是对类名和属性名进行硬编码。正如您从上面的代码片段中看到的那样,我将 a 数据集中的值分配给属性。计划是将值作为列名、属性名和父节点存储在数据库中。因此 P 节点中的 PName 属性将来自列名 Pname。我希望以这样一种方式进行设计,即我的代码中不会有任何硬编码。

对不起,请多多包涵,如果我说得不对,请告诉我。

4

2 回答 2

1

长问题值得长答案:

I.首先,一个小小的证书:我已经在类/程序集生成方面工作了一段时间。事实上,您可以使用CodeDom(首选方法)或IL Emit来做到这一点。但你可能不应该。

  • 反对这一点的第一个论点是您的 XML 模型实际上并没有那么有用。好的,所以您有一个想要转换为类的 XML。为此,您将以某种方式将该 XML 转换为代码(C# 或 VB 甚至 IL),然后在运行时编译它以创建一个动态类。那么,为什么不直接使用代码而不是 XML?
  • 上述观点有一个推论:如果您在设计时指定类,为什么不编译该类(因此,在编译时生成它)?

二、您的设计驱动程序不是硬代码

  • 首先是哲学分析:你不想硬编码代码,这是一个悖论。
  • 最好的做法是尽量减少源代码中的硬编码字符串,主要是因为 (1) 这些字符串会发生变化 (2) 它可能会使测试更容易。我们可以从这个定义中提取两件事:
    • 您应该避免硬编码字符串,而不是程序结构
    • 您应该只配置那些在编译时预计会改变(“动态”)或您不知道的东西。数据库结构几乎不是这种情况。

现在,抽象地思考一下,你能避免硬编码吗?在您的示例中,您已经使用了一些字符串来引用您将要处理的 XML 文件中的数据。如果没有有关您要处理的数据的任何信息,程序将如何工作?

(是的,有答案)

...

答:当您只是呈现数据时,即完整的数据结构与程序逻辑无关。这方面的例子是文本编辑器。文本编辑器不需要事先了解数据。您渲染它,因为它存在于文件中。

但是,在您的情况下,数据库是数据的“主”。试图将它与您的程序分开是没有用的。

于 2012-06-01T23:49:41.357 回答
0

只解析 XML 而不是创建程序集不是更容易吗?您可以使用 XmlSchema 及其子对象来提取数据库中所需的所有信息。您可以使用处理 XML 文档的通用框架来操作 XML 输出。或者,如果您确实需要该程序集,您可以先更改 XML,然后将其反序列化为一个对象。

但是,如果您的客户端代码在编译时不应该知道程序集的 CLR 类型,我认为首先创建程序集没有多大意义,您最好创建一个通用的中间数据格式您可以根据需要转换为 XML 或数据库列。

于 2012-06-01T18:25:19.973 回答