【问题标题】:Converting xsd enums to C#将 xsd 枚举转换为 C#
【发布时间】:2011-10-06 12:29:16
【问题描述】:

我有一个 xsd 文件,从中生成一个 C# 类。为了提供更容易的维护,我只想在 xsd 文件中定义一个枚举,这样当我必须更改枚举时,我只需在一个地方更新它。我知道如何创建枚举,但是在生成 C# 代码时,我需要枚举成员具有自定义值,因此结果类似于:

public enum SetupTypeEnum {
    None = 0,
    NewInstall = 1,
    Modify = 2,
    Upgrade = 4,
    Uninstall = 8
}

有没有办法写 xsd 来完成这个?

【问题讨论】:

  • 您是在编写自己的工具来生成 C# 代码,还是有一些标准工具可以从 XSD 生成 C# 代码?
  • 现在我正在使用 xsd.exe。我真的没有时间创建自己的工具。

标签: c# .net xml xsd


【解决方案1】:

您可以为您的 xsd 文件添加特定于代码生成的注释(这只适用于 svcutil,不适用于 xsd.exe)。枚举的 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”,您可以找到一个示例on this msdn page

更新: John Saunders 在他的评论中正确地指出,如果您使用 xsd.exe,这将不起作用。但是,如果您使用 svcutil.exe 创建 C# 代码,则注释将起作用。

svcutil.exe使用示例:

svcutil /dconly "D:\test.xsd" /o:"D:\test.cs"

如果您使用svcutil 而不是xsd.exe,则生成的代码将略有不同。最重要的区别是svcutil 将为 DataContractSerialization 而不是 XmlSerialization 生成属性。

【讨论】:

  • -1:有趣的链接,我不知道这个功能;但是如果 OP 使用的是 XSD.EXE,那么他使用的是 XML 序列化,并且EnumerationValue 是数据协定序列化器的一个功能。
  • @John:是的,这确实适用于数据合约序列化程序,我认为它也适用于xsd.exe。但是,如果您使用 svcutil 从 xsd 文件创建代码,则注释会起作用。
  • 我使用 xsd 的原因是因为我没有意识到我可以通过其他任何方式做到这一点。虽然这最终可能比我想投入更多的编码,但答案实际上是我正在寻找的完美。
【解决方案2】:

XSD 中的“枚举”概念与 C# 中的“枚举”概念无关。

XML Schema 中的“枚举”是一种将类型的可能词法值限制为 枚举 值列表的方法。例如:

<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>

这种类型将值空间限制为一组“夏季”月份(7 月、8 月和 9 月)。

显然,这与 C# 或我知道的任何其他编程语言中的“枚举”没有对应关系。

【讨论】:

  • 虽然我理解您的意思,但 xsd.exe 会将 xsd 枚举转换为 C# 枚举,因此存在一些相关性。它只是没有我希望的那么深。
  • 它将一些 xsd枚举转换为enum。即使在那里,也只有默认值。
【解决方案3】:

我相信 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)

【讨论】:

  • 谢谢。您是否有一个链接可以显示链接值的类示例?
  • @Drew Burchett:这取决于您将如何使用它,但我添加了适用于您的示例的代码,并假设您希望其他枚举以类似的方式用 2 的幂表示。
猜你喜欢
  • 2020-08-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-12
  • 1970-01-01
  • 2021-01-04
  • 2015-06-10
相关资源
最近更新 更多