[C++/CLI] DefaultValueAttribute "corrupt" Xml generatie?

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • daan.timmer
  • Registratie: Februari 2010
  • Laatst online: 07-09 13:19
Beste Tweakers,

ik ben tegen een vervelend probleem opgelopen tijdens het programmeren (veel voorkomende zin lijkt mij :P)

Ik maak gebruik van een app.Config file, waar ik custom-classes uit laat genereren d.m.v. de ConfigurationManager::GetSection();
ConfigManager:
C++:
1
ConfigSaveable ^ config =  static_cast<ConfigSaveable ^>(ConfigurationManager::GetSection(rootName));


app.Config:
XML:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <configSections>
        <section name="VideoPoolConfig" type="XpressCommon.Config.ConfigSectionHandler, XpressCommon" />
    </configSections>

    <VideoPoolConfig Max="1000" Min="0" type="XpressVideo.Config.VideoPoolConfig, XpressVideo">
        <parts>
            <part duration="4" priority="0" />
            <part duration="6" priority="1" />
            <part duration="8" priority="0" />
        </parts>
    </VideoPoolConfig>
</configuration>

ConfigSectionHandler:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
Object ^ ConfigSectionHandler::Create(Object ^ parent, Object ^ configContext, XmlNode ^ section)
{
    XPathNavigator ^ xpn = section->CreateNavigator();
    String ^ typeOfObject = static_cast<String ^>(xpn->Evaluate("string(@type)"));

    Type ^ t = Type::GetType(typeOfObject);

    XmlSerializer ^ ser = gcnew XmlSerializer(t);
    XmlNodeReader ^ xnr = gcnew XmlNodeReader(section);

    return ser->Deserialize(xnr);
}

VideoPoolConfig:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
        [System::Xml::Serialization::XmlRoot("VideoPoolConfig")]
        public ref class VideoPoolConfig : public XpressCommon::Config::ConfigSaveable
        {
        private:
            array<int> ^ durations;
            array<int> ^ priorities;

        public:
            [System::ComponentModel::DefaultValue(0)]
            [System::Xml::Serialization::XmlAttribute("Min")]
            property int Min;

            [System::ComponentModel::DefaultValue(1000)]
            [System::Xml::Serialization::XmlAttribute("Max")]
            property int Max;

            [System::Xml::Serialization::XmlArray("parts")]
            [System::Xml::Serialization::XmlArrayItem("part", Part::typeid)]
            property System::Collections::Generic::List<Part ^> ^ parts;
--snip


Bovenstaande code (zit nog wel wat meer omheen, maar alleen het boordnodige ff tussenuitgeknipt) werkt perfect.

Nu wilde ik het liefst ook DefaultValue's in kunnen instellen, zoals bij sommige elementen te zien zijn d.m.v.
System::ComponentModel::DefaultValue

Nu werkt dit ook perfect. Ik maak hiervoor gebruik van een van C# naar C++/CLI omgezet stuk code van http://www.codeproject.com/KB/dotnet/DefValInit.aspx, zie de AOP code.

Echter ben ik er zojuist achtergekomen dat als de DefaultValue hetzelfde is als de value die in de XML staat, hij dit wel goed inleest. De property wordt keurig 2x geaccessed, eerst voor de DefaultValue-init en vervolgens door de configManager. Maar als ik het e.e.a. weer wil opslaan (wat ik doe d.m.v. onderstande snippet)
C++:
1
2
3
4
5
6
7
8
        //Create a new XmlSerializer
        XmlSerializer ^ xs = gcnew XmlSerializer(object->GetType(), "");

        //Create a new StringWriter
        StringWriter ^ writer = gcnew StringWriter();

        //Serialize the object to the stringwriter stream;
        xs->Serialize(writer, object, nullptr);

Dan behoud de property niet zijn waarde en komt hij niet in de gegenereerde XML file te staan.
XML:
1
2
3
4
5
6
7
<VideoPoolConfig>
  <parts>
    <part duration="4" />
    <part duration="6" priority="1" />
    <part duration="8" />
  </parts>
</VideoPoolConfig>
is de output die hij vervolgens genereerd. priority heeft als default = 0 en zoals je ook ziet zijn de Min en Max ook weg uit de VideoPoolConfig.

Als ik door de code heenstap als hij aan het XmlSerialize-en is, en ik zet mijn breakpoints op de properties die hij moet gaan opslaan. Dan zal hij twee keer, vanuit een ander stuk assembler dezelfde property lezen indien deze niet gelijk is aan de DefaultValue. Als deze wel gelijk is aan de DefaultWaarde (en dus niet weggeschreven zal worden) dan wordt de property maar 1x geaccessed. Vanuit dezelfde assembly lijn als de eerste access van de niet-defaultvalue.

Ik hoop dat ik een beetje duidelijk ben geweest. Indien ik wat meer informatie moet geven, dan doe ik dat uiteraard graag![/small]

[edit]

Nou, na nog maar een keer google(de zoveelste, was al een tijdje opzoek) en een zooi topics doornemen op verscheidene fora ben ik er achter dat het een "feature" is van XmlSerialization class.

http://msdn.microsoft.com...ry/83y7df3e(v=VS.90).aspx
http://msdn.microsoft.com/en-us/library/swxzdhc0(vs.71).aspx

Er staat echter nergens dat als de value gelijk is aan de defaultvalueattribute dat deze dan weggelaten wordt. Maar hier ga ik dan maar vanuit. Want het werkte dus wel, maar ik vertrouwde het toch niet. Maja, nu dan toch maar wel.

Ik laat het bericht zo, zodat andere dit topic misschien ook ooit kunnen vinden :-)

[ Voor 7% gewijzigd door Woy op 10-12-2010 17:39 . Reden: small tag verwijderd ]


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 01:28

.oisyn

Moderator Devschuur®

Demotivational Speaker

Ik laat het bericht zo, zodat andere dit topic misschien ook ooit kunnen vinden :-)
Prima, maar haal dan wel even die small tag weg, want dit lijkt natuurlijk nergens op. :)

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Acties:
  • 0 Henk 'm!

  • daan.timmer
  • Registratie: Februari 2010
  • Laatst online: 07-09 13:19
Hah, ja, zag het nadat ik op submit gedrukt had. Echter moest ik weg (zat op werk) en zag toen pas dat het er zo "lelijk" uit zag.
Dank Woy voor de edit :-)