【问题标题】:Preserving Order In Sequence of Choices (LINQ To XSD)保留选择序列中的顺序 (LINQ To XSD)
【发布时间】:2009-10-28 15:50:19
【问题描述】:

鉴于以下 XML 示例,我们可以想象一个模式将 Root 定义为包含 Type1 和 Type2 之间的一系列无限制选择。

<Root>
    <Type1 />
    <Type2 />
    <Type2 />
    <Type1 />
</Root>

我正在测试从 XSD.exe 工具迁移,虽然它增加了类型安全,但有很多小烦恼。在这种情况下,XSD 工具只是在 Root 中创建一个 System.Object 类型的数组,您必须弄清楚其中的对象类型(Type1 或 Type2)。它并不完全优雅,但至少你保持秩序。

问题是当 LINQ to XSD 创建对象时,它将 Root 定义为具有两个独立的 Type1 和 Type2 列表。这很好,因为它是类型安全的,但我现在似乎失去了元素的顺序。我从 codeplex 上的源代码构建了 LINQ to XSD。

使用 LINQ to XSD,如何保持这些元素的顺序?

【问题讨论】:

  • 好吧,您已经提出了仅有的两个选项。要么你得到一个保留顺序的弱类型集合,要么你得到每个类型的强类型集合。假设您根本不使用任何 XML - 您将如何编写一个纯代码对象,其中包含一个具有多种类型的强类型集合?
  • 我的问题是如何使用 Linq to XSD 在这种情况下保留元素的顺序。我意识到有一个混合类型的集合,它们需要是 System.Object (或它们共有的任何父级)。在这种情况下,我愿意放弃强类型对象,W/Linq to XSD 以保持顺序。我希望有一种方法可以强迫它这样做。在我的用例中,顺序很重要,所以我不能使用 Linq to XSD,尽管我真的很想使用它,因为它比 XSD.exe 有很多优势
  • 你可以通过继承来做到这一点。如果 Type1 和 Type2 都有一个公共基类,则可以有一个 IList。现在你有一个单一的强类型列表,并且顺序被保留了。遍历列表时,只需检查当前对象的类型。 foreach(BaseType el in elements) { if (el is Type1) ... else if (el is Type2) ... }
  • 小猪退出其他 cmets,看起来您回答了自己的问题。要获得订单,您必须使用某种基类,无论是对象还是您创建的对象,并在运行时进行类型检查。我建议你添加一个答案然后接受它。 :-) 如果我没记错的话,你会得到一个徽章。

标签: c# linq xsd xsd.exe linq-to-xsd


【解决方案1】:

如何围绕 Choice 创建一个包装器?像这样限制它访问的类型:

class Choice
{
    private object _value;

    public ChoiceEnum CurrentType { get; private set; }

    public Type1 Type1Value
    {
        get { return (Type1) _value; }
        set { _value = value; CurrentType = ChoiceEnum.Type1; }
    }

    public Type2 Type2Value
    {
        get { return (Type2) _value; }
        set { _value = value; CurrentType = ChoiceEnum.Type2; }
    }
}

这是一个简化版本,您必须添加更多验证(如果_value 的类型正确,_value 的当前类型是什么等)。

然后,您可以使用 LINQ 对其进行过滤:

var q1 = from v in root.Sequence
         where v.CurrentType == ChoiceEnum.Type1
         select v.Type1;

或者您可以在 Root 中创建方法来包装查询。

【讨论】:

  • 好建议。这应该可行,但确实决定了 XSD 本身的设计,这是不幸的,有时是不可能的(例如行业标准模式)。我们在团队中使用的许多模式都是由我们创建的,因此我们可以使用这种技术。
【解决方案2】:

Linq2Xsd 仅在存在 xsd:choice 元素时才会触发序列。

幸运的是,我能够删除我正在使用的 Amazon XSD 的 xsd:choice(我只是没有使用 MerchantOrderID),这使得序列可以正确地保存在 xml 的 ToString() 中。

            <xsd:choice>                                <--- removed line
                <xsd:element ref="AmazonOrderID"/>
                <xsd:element ref="MerchantOrderID"/>    <--- removed line
            </xsd:choice>                               <--- removed line

            <xsd:element name="ActionType" minOccurs="0" maxOccurs="1">
                <xsd:simpleType>
                    <xsd:restriction base="xsd:string">
                        <xsd:enumeration value="Refund"/>
                        <xsd:enumeration value="Cancel"/>
                    </xsd:restriction>
                </xsd:simpleType>
            </xsd:element> 

然后生成的代码在构造函数中正确地保留了顺序

contentModel = new SequenceContentModelEntity(
               new NamedContentModelEntity(XName.Get("AmazonOrderID", "")), 
               new NamedContentModelEntity(XName.Get("ActionType", "")), 
               new NamedContentModelEntity(XName.Get("CODCollectionMethod", "")), 
               new NamedContentModelEntity(XName.Get("AdjustedItem", "")));

您也可以通过自己对其进行子类化来手动执行此操作,但我不确定这将如何与 xsd:choice 一起使用。这是described here,但我还没有测试过。

【讨论】:

    猜你喜欢
    • 2010-11-29
    • 1970-01-01
    • 2011-11-18
    • 2021-06-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-15
    • 1970-01-01
    相关资源
    最近更新 更多