2016-08-04 42 views
5

Mam następujące definicje enum ...Jak rozwiązać problem "Obie nazwy X używają typu XML, użyj atrybutów XML, aby określić unikalną nazwę XML i/lub przestrzeń nazw dla typu"?

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

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

... a potem mam następujące klasy ...

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

... a gdy próbuję serializować wystąpienie UISettings z ...

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

... pojawia się następujący błąd:

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. 

Próbowałem użyć attribubtes XmlType i wszelkiego rodzaju rozwiązań opublikowanych w Internecie, ale nic nie działa. Nazwa typu XML jest zawsze TableOfDisplayMode, jak wspomniano w błędzie.

Jedynym rozwiązaniem w tej chwili jest zmiana nazwy jednego z wyliczeń, np. do DisplayMode_, ale uważam, że raczej brzydki.

Odpowiedz

5

Trzeba zapewnić Namespace za pomocą atrybutu XmlElement na właściwości klasy UISettings:

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

Gdy zastosowano tutaj będzie to twoje wyjście odcinkach:

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

Alternatywnie, i może być czystszy, możesz podać Przestrzeń nazw na typy:

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

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

To serializacji jako:

<?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> 
+0

Oh my ... działa! Dzięki. Ale dlaczego muszę określić przestrzeń nazw? Dlaczego serializator po prostu nie używa nazwy właściwości jako przestrzeni nazw? – ViRuSTriNiTy

+1

Serializator domyślnie nie używa przestrzeni nazw i generowanie ich w razie potrzeby prawdopodobnie spowodowałoby więcej scenariuszy. Przestrzenie nazw są w tym sensie podobne do przestrzeni nazw w języku C#. ma znaczenie, czy 'Label' pochodzi z przestrzeni nazw System.Windows.Forms lub System.Web.WebControls. – rene

+0

OK, ale dlaczego konieczne jest dodanie atrybutu 'xmlns' do węzłów DisplayMode? Jakiś konkretny powód? – ViRuSTriNiTy

1

Zdaję sobie sprawę, ta odpowiedź pochodzi prawdopodobnie zbyt późno dla PO, ale nie ma sposobu, aby to zrobić bez używania nazw, więc mam zamiar zostawić odpowiedź tutaj na wypadek, gdyby ktoś po mnie podszedł i potrzebuje rozwiązania.

Problem polega na tym, że sposób, w jaki XmlSerializer nazywa się typ X<Y>, polega na nadaniu mu nazwy XOfY. Tak więc, gdy masz dwa typy, które pochodzą od Table<TDisplayMode>, otrzymasz ten błąd, ponieważ oba będą znane wewnętrznie jako TableOfDisplayMode, mimo że używają różnych wyliczeń.

To dlatego, że ItemTable i EffectiveItemPermissionTable są w rzeczywistości nie dziedziczą z tego samego typu! Jeden dziedziczy po Table<ItemTable.DisplayMode>, a drugi od Table<EffectiveItemPermissionTable.DisplayMode>. Nie znaczy to, że ogranicza się to do dziedziczenia; napotkasz ten sam problem, jeśli spróbujesz użyć ich bezpośrednio na tym samym wykresie obiektów XML.

Teraz, w przypadku nieobsługiwanego odpowiednika tego problemu, wystarczy obetrzeć jeden z dwóch typów [XmlType] i nazwać to dniem. Ale nie możesz tego zrobić tutaj. Podczas gdy Table<ItemTable.DisplayMode> i Table<EffectiveItemPermissionTable.DisplayMode> są różnymi typami, mają one tę samą definicję klasy, więc próbując użyć [XmlType], nadajesz im inne imię, ale wciąż masz to samo imię.

Co więc można zrobić? XmlAttributeOverrides na ratunek!Pozwala zastąpić nazwy XmlSerializer daje zamkniętych typów generycznych, co oznacza, że ​​można wreszcie dać inną nazwę Table<ItemTable.DisplayMode> i 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); 

i voila! Zakładając, że wstawiłeś także [XmlType] z różnymi nazwami dla swoich wyliczeń DisplayMode, tak, że ich nazwy również nie powodują konfliktu, masz już działającą konfigurację!