【问题标题】:Calling subclass properties in code-generated (via xsd.exe) classes在代码生成(通过 xsd.exe)类中调用子类属性
【发布时间】:2010-12-27 16:52:04
【问题描述】:

我正在尝试从具有两个扩展通用 complexType 的复杂类型的 XSD 生成代码。继承者有一个名为“value”的公共属性,它有不同的类型。当然,由于 XSD 规则,我不能把它放在我的基本类型上。我的意图是多态地调用基类型上的属性,这将调用子类上的正确方法。这可能吗?

这是我的 XSD

<xs:complexType name="Property">
    <xs:attribute name="name" type="xs:string" use="required"/>
</xs:complexType>
<xs:complexType name="StringProperty">
    <xs:complexContent>
        <xs:extension base="Property">
            <xs:attribute name="value" type="xs:string" use="required"/>
        </xs:extension>
    </xs:complexContent>
</xs:complexType>
<xs:complexType name="BooleanProperty">
    <xs:complexContent>
        <xs:extension base="Property">
            <xs:attribute name="value" type="xs:boolean" use="required"/>
        </xs:extension>
    </xs:complexContent>
</xs:complexType>

这会生成以下代码:

public partial class Property {

    private string nameField;

    /// <remarks/>
    [System.Xml.Serialization.XmlAttributeAttribute()]
    public string name {
        get {
            return this.nameField;
        }
        set {
            this.nameField = value;
        }
    }
}

public partial class StringProperty : Property {

    private string valueField;

    /// <remarks/>
    [System.Xml.Serialization.XmlAttributeAttribute()]
    public string value {
        get {
            return this.valueField;
        }
        set {
            this.valueField = value;
        }
    }
}

public partial class BoolProperty : Property {

    private bool valueField;

    /// <remarks/>
    [System.Xml.Serialization.XmlAttributeAttribute()]
    public bool value {
        get {
            return this.valueField;
        }
        set {
            this.valueField = value;
        }
    }
}

这就是我想做的:

            // ConfigProperties is an array of Property objects
            foreach (Property property in config.ConfigProperties)
            {
                // Doesn't compile since Property.value doesn't exist in the base class.
                Console.WriteLine(property.value);
            }

我尝试在 Property 对象上实现一个“值”getter 属性,希望子类的“值”属性定义能够隐藏它,但这并不能解决问题:

public partial class Property
{
    public virtual string value
    {
        get { throw new NotImplementedException(); } // this method is called instead of the Property subclass methods
    }
}

后续问题编辑:答案证实了我担心这是不可能的。是否仍然可以通过某种方式执行以下操作:

            foreach (Property property in config.ConfigProperties)
            {
                somevalue = property.GetValue();
            }

其中 GetValue() 是一种方法,它通过它实际使用的 Property 的子类来确定它应该具有什么返回类型?请原谅我非常懒惰。我相信it's a virtue。 =)

【问题讨论】:

    标签: c# xsd code-generation


    【解决方案1】:

    您正在反序列化为Property 对象,因此序列化程序会创建Property 类型的对象。您不会在运行时知道您是否拥有BoolPropertyStringProperty

    您需要从 XML 中提取 StringProperties,将它们反序列化为 StringProperty 对象,然后对 BoolProperties 进行同样的操作。

    然后您可以将它们组合成一个Property 类型的列表。只要您在实现类中覆盖的基类上创建virtual property,应用程序就会像预期的那样运行。


    回复作者的编辑
    它不会起作用,因为您当时没有正确的信息。您必须将您的对象显式反序列化为 StringProperty 才能让 .NET 识别您的属性。您将永远无法检测到函数中的属性类型。

    如果你有正确类型的Property对象,你可以创建一个扩展方法来方便:

    public string GetValue(this Property property)
    {
        if(property is StringProperty) return ((StringProperty)property).Value;
        else if ...
    }
    

    但您需要知道正确的类型,如果您将实体反序列化为 Property 对象,您不知道。

    【讨论】:

    • 我猜的差不多了。我认为如果没有对扩展和覆盖的 XSD 限制,这会更容易。谢谢简!
    【解决方案2】:

    我认为不可能按照您尝试的方式进行。

    不过,您可以利用部分类机制。

    例如,您可以为 Property 分部类添加另一个文件,并添加一个名为“public virtual string ValueToString()”的虚拟方法,在 StringProperty 和 BoolProperty 中覆盖它(也可以通过分部类机制)。这样你就可以使 foreach 工作(调用 property.ValueToString())。

    当然这意味着你必须在生成类之后进行自定义工作,但我没有看到其他方法。

    【讨论】:

    • 感谢您的快速回复!不过,我在上面有一个后续问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-03
    • 2011-05-18
    • 1970-01-01
    • 1970-01-01
    • 2022-01-20
    • 1970-01-01
    相关资源
    最近更新 更多