在代码生成(通过xsd.exe)类中调用子类属性

时间:2009-12-17 15:15:57

标签: c# xsd code-generation

我正在尝试从XSD生成代码,该代码具有两个扩展常见complexType的complexType。继承者有一个名为“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对象上实现一个“value”getter属性,希望子类的“value”属性定义能够隐藏它,但这并不能解决问题:

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。 =)

2 个答案:

答案 0 :(得分:2)

您正在反序列化为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个对象,则不知道该类型。

答案 1 :(得分:1)

我认为不可能按照你想要的方式去做。

但是你可以利用部分类机制。

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

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