我有一个 xsd 文件,我从中生成一个 C# 类。为了提供更轻松的维护,我想仅在 xsd 文件中定义一个枚举,这样当我必须更改枚举时,我只需在一处更新它。我知道如何创建枚举,但是生成 C# 代码时,我需要枚举成员具有自定义值,因此结果将类似于:
public enum SetupTypeEnum {
None = 0,
NewInstall = 1,
Modify = 2,
Upgrade = 4,
Uninstall = 8
}
有没有办法编写xsd来完成这个?
您可以将特定于代码生成的注释(这只适用于 svcutil,不适用于 xsd.exe)添加到您的 xsd 文件中。您的枚举的 xsd 定义将是这样的:
<xs:simpleType name="SetupTypeEnum">
<xs:restriction base="xs:string">
<xs:enumeration value="None">
<xs:annotation>
<xs:appinfo>
<EnumerationValue xmlns="http://schemas.microsoft.com/2003/10/Serialization/">0</EnumerationValue>
</xs:appinfo>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="NewInstall">
<xs:annotation>
<xs:appinfo>
<EnumerationValue xmlns="http://schemas.microsoft.com/2003/10/Serialization/">1</EnumerationValue>
</xs:appinfo>
</xs:annotation>
</xs:enumeration>
...
</xs:restriction>
</xs:simpleType>
这些注释允许您显式定义每个枚举值的数值。如果您搜索“EnumerationValue”,您可以在 在此 msdn 页面上找到示例。
更新:John Saunders 在他的评论中正确指出,如果您使用 xsd.exe,这将不起作用。但是,如果您使用 svcutil.exe 创建 C# 代码,则注释将起作用。
使用
svcutil.exe
的示例:
svcutil /dconly "D:\test.xsd" /o:"D:\test.cs"
如果您使用
svcutil
而不是 xsd.exe
,那么生成的代码将略有不同。最重要的区别是 svcutil
将为 DataContractSerialization 而不是 XmlSerialization 生成属性。
XSD 中的“枚举”概念与 C# 中的“枚举”概念无关。
XML 模式中的“枚举”是一种将类型的可能词汇值限制为“枚举”值列表的方法。例如:
<xs:simpleType name="SummerMonth">
<xs:restriction base="xs:gMonth">
<xs:enumeration value="--07"/>
<xs:enumeration value="--08"/>
<xs:enumeration value="--09"/>
</xs:restriction>
</xs:simpleType>
显然,这与 C# 或我所知道的任何其他编程语言中的“枚举”没有对应关系。
我认为 XSD 枚举是比 .NET 枚举更纯粹的枚举实现,因为它们不需要也不支持与枚举名称关联的数值。当然,生成的代码(即 .NET 代码)将在内部将数值与每个命名值关联起来,但这是一个实现细节,它不是 XSD 标准定义的枚举本质所固有的。在这个枚举的纯粹实现中,我相信将显式数值与每个枚举名称相关联的正确方法是定义一个单独的集合/类,将枚举值链接到数值。或者定义其他枚举值来表示您支持的组合值 (NewInstallOrModify)。
编辑:
这是转换器的示例。
// Generated code
public enum SetupTypeEnum
{
None,
NewInstall,
Modify,
Upgrade,
Uninstall
}
// End generated code
public struct IntMappedEnum<T> where T : struct
{
public readonly int originalValue;
public IntMappedEnum(T value)
{
originalValue = (int)Enum.ToObject(typeof(T), value);
}
public IntMappedEnum(int originalValue)
{
this.originalValue = originalValue;
}
public static implicit operator int(IntMappedEnum<T> value)
{
return 1 << value.originalValue;
}
public static implicit operator IntMappedEnum<T>(T value)
{
return new IntMappedEnum<T>(value);
}
public static implicit operator IntMappedEnum<T>(int value)
{
int log;
for (log = 0; value > 1; value >>= 1)
log++;
return new IntMappedEnum<T>(log);
}
public static explicit operator T(IntMappedEnum<T> value)
{
T result;
Enum.TryParse<T>(value.originalValue.ToString(), out result);
return result;
}
}
class Program
{
static void Main(string[] args)
{
SetupTypeEnum s = SetupTypeEnum.Uninstall;
IntMappedEnum<SetupTypeEnum> c = s;
int n = c;
IntMappedEnum<SetupTypeEnum> c1 = n;
SetupTypeEnum s1 = (SetupTypeEnum)c1;
Console.WriteLine("{0} => {1} => {2}", s, n, s1);
}
}
编辑2:
如果您的枚举从 0 开始(如您的示例所示),这两个更改对于我的示例来说是必要的:
更新了 int 转换器:
public static implicit operator int(IntMappedEnum<T> value)
{
return (value.originalValue == 0)?0:1 << (value.originalValue - 1);
}
int log
之后的行应该是:
for (log = 0; value > 0; value >>= 1)
多年后,我认为这已部分实施。我不确定您是否可以为每个枚举提供特定值,但 XSD C# 类生成器能够将 XSD 枚举从 0..n 转换为 C# 枚举,以获得 n 个枚举值。
<?xml version="1.0" encoding="utf-8"?>
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:simpleType name="Status" final="restriction">
<xs:restriction base="xs:string">
<xs:enumeration value="Enabled"></xs:enumeration>
<xs:enumeration value="Disabled"></xs:enumeration>
<xs:enumeration value="Running"></xs:enumeration>
</xs:restriction>
</xs:simpleType>
<xs:element name="My">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute type="Status" name="Status" use="optional"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:schema>
运行转换器后 (
xsd My.xsd /classes
)
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
using System.Xml.Serialization;
//
// This source code was auto-generated by xsd, Version=4.8.3928.0.
//
/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.8.3928.0")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true)]
[System.Xml.Serialization.XmlRootAttribute(Namespace="", IsNullable=false)]
public partial class My {
private Status statusField;
private bool statusFieldSpecified;
private string valueField;
/// <remarks/>
[System.Xml.Serialization.XmlAttributeAttribute()]
public Status Status {
get {
return this.statusField;
}
set {
this.statusField = value;
}
}
/// <remarks/>
[System.Xml.Serialization.XmlIgnoreAttribute()]
public bool StatusSpecified {
get {
return this.statusFieldSpecified;
}
set {
this.statusFieldSpecified = value;
}
}
/// <remarks/>
[System.Xml.Serialization.XmlTextAttribute()]
public string Value {
get {
return this.valueField;
}
set {
this.valueField = value;
}
}
}
/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.8.3928.0")]
[System.SerializableAttribute()]
public enum Status {
/// <remarks/>
Enabled,
/// <remarks/>
Disabled,
/// <remarks/>
Running,
}