创建实例并分配运行时程序集的属性

本文关键字:程序集 属性 运行时 分配 实例 创建 | 更新日期: 2023-09-27 18:36:13

>我需要创建一个通用解决方案,用于创建从 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。在这种情况下,我知道属性和期望的内容,因此创建实例和获取属性以及设置值将起作用。我知道一个投资组合将有一系列投资组合投资组合。

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(不仅仅是上述)并生成程序集。我已经生成了组装,但现在我的问题是如何为不知道其中存在哪些属性的类动态分配属性?我的意思是,在创建通用解决方案时,我如何知道一个类正在使用另一个类的对象列表。因此,与其硬编码类名和属性名,不如有一种方法可以获取实例和属性。正如您从上面的代码片段中看到的,我将数据集中的值分配给属性。计划是将值作为列名、属性名和父节点存储在数据库中。所以 P 节点中的 PName 属性将来自列名 Pname。我希望设计的方式是我的代码中不会有任何硬编码。你能用一些例子或设计理念来建议我吗?

对不起,请耐心等待,如果我不讲道理,请告诉我。

创建实例并分配运行时程序集的属性

长问题值得长答案:

I. 首先,一个小凭据:我已经使用类/程序集生成一段时间了。实际上,您可以使用 CodeDom(首选方法)或 IL 发出来执行此操作。但你可能不应该。

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

II. 这里的设计驱动程序不是硬代码

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

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

(是的,有答案)

答:当你只是呈现数据时,也就是说,完整的数据结构与程序逻辑无关。这方面的示例是文本编辑器。文本编辑器不需要事先了解数据。您可以按文件中存在的方式呈现它。

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

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

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