如何解决“两者都使用XML类型名称X,使用XML属性为类型指定唯一的XML名称和/或名称空间”?

时间:2016-08-04 08:41:23

标签: c# serialization attributes

我有以下枚举定义......

namespace ItemTable
{
  public enum DisplayMode
  {
    Tiles,
    Default
  }
}

namespace EffectiveItemPermissionTable
{
  public enum DisplayMode
  {
    Tree,
    FullPaths
  }
}

...然后我有以下课程......

public class Table<TDisplayMode>
  where TDisplayMode: struct
{
  // public
    public TDisplayMode DisplayMode
    { 
      get { return mDisplayMode; }
      set { mDisplayMode = value; }
    }

  // private
    private TDisplayMode mDisplayMode;
}

public class ItemTable : Table<ItemTable.DisplayMode>
{}

public class EffectiveItemPermissionTable : Table<EffectiveItemPermissionTable.DisplayMode>
{}

public class UISettings
{
  public UISettings()
  {
    ItemTable = new ItemTable();
    EffectiveItemPermissionTable = new EffectiveItemPermissionTable();
  }

  public ItemTable ItemTable { get; set; }
  public EffectiveItemPermissionTable EffectiveItemPermissionTable { get; set; }
}

...当我尝试使用...

序列化UISettings实例时
System.Xml.Serialization.XmlSerializer lSerializer =
  new System.Xml.Serialization.XmlSerializer(typeof(UISettings));

...我收到以下错误:

Types 'UISettings.Table`1[EffectiveItemPermissionTable.DisplayMode]' and
'UISettings.Table`1[ItemTable.DisplayMode]' both use the XML type name,
'TableOfDisplayMode', from namespace ''.

Use XML attributes to specify a unique XML name and/or namespace for the type.

我曾尝试使用XmlType attribubtes和网上发布的各种解决方案,但没有任何效果。 XML类型名称始终为TableOfDisplayMode,如错误中所述。

现在唯一的解决方案是重命名其中一个枚举,例如:到DisplayMode_,但我觉得相当难看。

2 个答案:

答案 0 :(得分:8)

您需要使用XmlElement类属性的UISettings属性提供Namespace

public class UISettings
{
    public UISettings()
    {

        ItemTable = new ItemTable();
        EffectiveItemPermissionTable = new EffectiveItemPermissionTable();
    }
    [XmlElement(Namespace = "Item")]
    public ItemTable ItemTable { get; set; }
    [XmlElement(Namespace = "Permissions")]
    public EffectiveItemPermissionTable EffectiveItemPermissionTable { get; set; }
}

在此处应用时,这将是您的序列化输出:

<?xml version="1.0" encoding="utf-16"?>
<UISettings xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">  
   <ItemTable xmlns="Item">    
      <DisplayMode>Tiles</DisplayMode>  
   </ItemTable>  
   <EffectiveItemPermissionTable xmlns="Permissions">    
       <DisplayMode>FullPaths</DisplayMode>  
   </EffectiveItemPermissionTable>
</UISettings>

或者,也许更干净,您可以在类型上提供命名空间:

[XmlType(Namespace="Item")]
public class ItemTable : Table<ItemTableNS.DisplayMode>
{ }

[XmlType(Namespace = "Permission")]
public class EffectiveItemPermissionTable : Table<EffectiveItemPermissionTableNS.DisplayMode>
{ }

这将序列化为:

<?xml version="1.0" encoding="utf-16"?>
<UISettings xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <ItemTable>
    <DisplayMode xmlns="Item">Tiles</DisplayMode>
  </ItemTable>
  <EffectiveItemPermissionTable>
    <DisplayMode xmlns="Permission">FullPaths</DisplayMode>
  </EffectiveItemPermissionTable>
</UISettings>

答案 1 :(得分:5)

我意识到这个答案可能对OP来说太迟了,但有一种方法可以在不使用命名空间的情况下做到这一点,所以我将在这里留下答案,以防有人跟我走后需要解决方案。

问题的原因是XmlSerializerX<Y>类型命名的方式是为其命名XOfY。因此,当您有两种类型都来自Table<TDisplayMode>时,您会收到该错误,因为尽管实际上使用了不同的枚举,但它们都会在内部被称为TableOfDisplayMode

这是因为ItemTableEffectiveItemPermissionTable实际上从同一类型继承!一个来自Table<ItemTable.DisplayMode>,另一个来自Table<EffectiveItemPermissionTable.DisplayMode>。并不是说这仅限于继承;如果你试图直接在同一个XML对象图中使用它们,你也会遇到同样的问题。

现在,对于这个问题的非通用对应物,你只需在这两种类型上点击[XmlType],并将其称为一天。但你不能在这里做到这一点。虽然Table<ItemTable.DisplayMode>Table<EffectiveItemPermissionTable.DisplayMode>是不同的类型,但它们共享相同的类定义,因此尝试使用[XmlType]时,您会给它们一个不同的名称,但名称仍然相同。 / p>

那你能做什么? XmlAttributeOverrides救援!它允许您覆盖XmlSerializer为封闭泛型类型提供的名称,这意味着您最终可以为Table<ItemTable.DisplayMode>Table<EffectiveItemPermissionTable.DisplayMode>指定其他名称:

var xmlOverrides = new XmlAttributeOverrides();

var xmlAttribs = new XmlAttributes();   
xmlAttribs.XmlType = new XmlTypeAttribute("TableOfItemTableDisplayMode");
xmlOverrides.Add(typeof(Table<ItemTable.DisplayMode>), xmlAttribs);

xmlAttribs = new XmlAttributes();
xmlAttribs.XmlType = new XmlTypeAttribute("TableOfEffectiveItemPermissionTableDisplayMode");
xmlOverrides.Add(typeof(Table<EffectiveItemPermissionTable.DisplayMode>), xmlAttribs);

System.Xml.Serialization.XmlSerializer lSerializer =
    new System.Xml.Serialization.XmlSerializer(typeof(UISettings), xmlOverrides);

瞧!现在假设你还为你的[XmlType]枚举添加了DisplayMode不同的名称,这样他们的名字也不会发生冲突,你就可以自己设置工作了!