【问题标题】:How to generate a List instead of an array in C# with xsd.exe如何使用 xsd.exe 在 C# 中生成列表而不是数组
【发布时间】:2013-03-13 15:58:27
【问题描述】:

我有一个 XML 架构 .xsd 文件,并使用 xsd.exe 工具生成包含所有 C# 类的文件。如果我在 XML 标记中有一系列元素,那么它将在 C# 中用数组表示。 失败是显而易见的。如何生成列表而不是数组?

我想在一个类中使用列表而不是固定大小的数组。

Book [] books = new Book[someFixSize];

List<Book> books =  new List<Book>();

我已经看到了一些关于此的较旧(非常古老)的问题,但没有一个提供令人满意的解决方案:/

这是最新的有用提示:http://www.stefanbader.ch/xsdcsarr2l-exe-refactor-xsd-array-to-list/

【问题讨论】:

  • 链接已损坏 (404)。

标签: c# xsd xml-serialization xsd.exe


【解决方案1】:

我在没有合约的情况下尝试使用 svcutil 时遇到了同样的问题,因此我编写了 xsdcsarr2l 工具。如果您有兴趣,我会花时间上传一个更新的版本,其中至少列表变量会自动初始化。另一方面,该项目足够轻巧,您可以获取源代码并使用 NRefactory 类自行改进。

【讨论】:

  • 您是否简单地将包含 Array [] 的行替换为 List?还是代码的其他行也被编辑了?
  • 只是涉及固定数组的行。该工具在 NRefactory 的帮助下解析 c#-source 并将其转换为 AST(抽象语法树)。因此,更改以稳健的方式应用。我们的想法是尽可能少地接触原版。
  • 是的,上传最新版本。
  • 完成。最新版本0.0.2 已上传。如果您遇到任何问题,请发送说明。
  • 该工具不再可用了吗?上面的链接坏了
【解决方案2】:

尝试使用 svcutil.exe

svcutil /o:myFile.cs /ct:System.Collections.Generic.List myXsd.xsd

【讨论】:

  • 我猜你唯一的选择是手动重构自动生成的代码。
  • 能否添加对 svcutil 的引用?
【解决方案3】:

Dan Field 有 a PowerShell script,它采用 xsd.exe 输出类并将其数组转换为通用列表。这对我来说很适合一个简单的课程,但我不知道它的扩展性如何。我已经粘贴了下面的脚本。像这样从命令提示符调用它:

"$(TargetFrameworkSDKToolsDirectory)xsd.exe" /c "$(ProjectDir)ImportedPartCanonical.xsd" "$(ProjectDir)ProjectCanonical.xsd" /n:Tallan.BT.PipelineComponents

powershell.exe -ExecutionPolicy Unrestricted -file "$(solutiondir)\PowerShellScripts\PostProcessXsdExe.ps1" ProjectCanonical.cs "$(SolutionDir)Tallan.BT.PipelineComponents\SerializedClasses\ProjectCanonical.cs"

查看链接了解完整说明。

# Author: Dan Field (dan.field@tallan.com)
# posted on blog.tallan.com/2016/03/10/xsd-exe-arrays-and-specified
# Purpose: fix the 'specified' attribute and convert arrays to list from XSD.exe generated classes

[CmdletBinding()]
Param(
    [Parameter(Mandatory=$true, Position=1)]
    [string]$inputFile,
    [Parameter(Mandatory=$true, Position=2)]
    [string]$outputFile,
    [switch]$DeleteInputFile
)

# Much faster than using Get-Content and/or Out-File/Set-Content
$writer = [System.IO.StreamWriter] $outputFile
$reader = [System.IO.StreamReader] $inputFile

# Used to track Specified properties
$setterDict = @{}

while (($line = $reader.ReadLine()) -ne $null)
{
    $thisStart = $line.IndexOf("this.") # Will be used for
    $brackets = $line.IndexOf("[]") # Indicates an array that will be converted to a Generic List

    # Assume that any private field that contains "Specified" needs to be grabbed
    if (($line.IndexOf("private") -gt -1) -and ($line.IndexOf("Specified") -gt -1))
    {
        # Get the field name
        $varName = $line.Split("{' ', ';'}", [System.StringSplitOptions]::RemoveEmptyEntries)[-1]

        # Use the field name as a key, minus the ending "Specified" portion, e.g. fieldNameSpecified -> fieldName
        # The value in the dictionary will be added to setters on the main property, e.g. "this.fieldNameSpecified = true;"
        $setterDict.Add($varName.Substring(0, $varName.IndexOf("Specified")), "this." + $varName + " = true;")

        # Output the line as is
        $writer.WriteLine($line)
    }
    # Find property setters that aren't for the *Specified properties
    elseif (($thisStart -gt -1) -and ($line.IndexOf(" = value") -gt -1) -and ($line.IndexOf("Specified") -lt 0))
    {
        # Get the field name
        $thisStart += 5
        $varName = $line.Substring($thisStart, $line.IndexOf(' ', $thisStart) - $thisStart)
        # see if there's a "Specified" property for this one
        if ($setterDict.ContainsKey($varName) -eq $true)
        {
            # Set the Specified property whenever this property is set
            $writer.WriteLine((' ' * ($thisStart - 5)) + $setterDict[$varName])
        }
        # Output the line itself
        $writer.WriteLine($line)
    }
    elseif ($brackets -gt 0) # change to List<T>
    {
        $lineParts = $line.Split(' ')
        foreach ($linePart in $lineParts)
        {
            if ($linePart.Contains("[]") -eq $true)
            {
                $writer.Write("System.Collections.Generic.List<" + $linePart.Replace("[]", "> "))
            }
            else
            {
                $writer.Write($linePart + " ")
            }
        }
        $writer.WriteLine();
    }
    else # Just output the original line
    {
        $writer.WriteLine($line)
    }
}

if ($DeleteInputFile -eq $true)
{
    Remove-Item $inputFile
}

# Make sure the file gets fully written and clean up handles
$writer.Flush();
$writer.Dispose();
$reader.Dispose();

【讨论】:

    【解决方案4】:

    试试Xsd2Code

    它生成列表而不是数组。不幸的是,我无法让它反序列化我的代码,但是将它与 xsd 生成的代码进行比较,它看起来非常相似。

    【讨论】:

    • nov2015 - xsd2code 供应商完全没有响应。无法获得试用许可证和电子邮件退回。我认为这已被放弃。
    【解决方案5】:

    我最近遇到了同样的问题。我想要 List 而不是 T[] 的唯一原因是因为我想在向 Web 服务发送请求之前添加项到数组中。

    我使用了 xsd.exe 生成部分类的事实。您可以添加自己的部分类,添加构造函数和 ADDT 方法,该方法将在分配给(新)最后一个元素之前使用 Array.Resize()。

    无需更改生成的代码或使用其他工具。

    【讨论】:

    • 有例子吗?
    猜你喜欢
    • 2013-10-01
    • 2011-11-08
    • 2011-01-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多