Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

(undefined ?) Redimensionnement de tableau dans une récurrence

15 réponses
Avatar
Gloops
Bonjour tout le monde,

Trou de m=E9moire : je cherche la doc sur le mot-clef undefined, mais je =

n'ai trouv=E9 =E7a que pour JScript, donc mauvaise pioche pour C# peut-=EA=
tre=20
bien. Alors j'ai essay=E9 avec null, mais =E7a n'a pas l'air d'=EAtre bie=
n =E7a.

Je suis en train de traduire en C# un projet que j'ai trouv=E9 en VB pour=
=20
s=E9rialiser un treeview (plagiat ? S=FBrement, un peu :) )

A toutes fins utiles, la source est l=E0 :
http://www.codeproject.com/KB/vb/TreeViewDataAccess/TreeViewDataAccess_de=
mo.zip

Et je suis en train de me cogner =E0 la vitre pour cette instruction :
ReDim Nodes(node.Nodes.Count - 1)

On me dit qu'=E0 la fin de ceci j'ai "Use of possibly unassigned field=20
'Nodes'". J'ai pris soin de v=E9rifier qu'il n'=E9tait pas nul, mais si i=
l=20
n'est pas d=E9fini il semblerait qu'il soit interdit de se demander si il=
=20
est nul ?


Accessoirement, on me dit aussi que Tag et Nodes doivent =EAtre "fully=20
assigned before control leaves the constructor". J'ai l'impression que=20
l'erreur est plus ou moins la m=EAme.


Voil=E0 le code (enfin un morceau) :

public TreeNodeData(TreeNode node)
{
this.Text =3D node.Text;
this.ImageIndex =3D node.ImageIndex;
this.SelectedImageIndex =3D node.SelectedImageIndex;
this.Checked =3D node.Checked;
this.Expanded =3D node.IsExpanded;
if ((node.Tag !=3D null) && node.Tag.GetType().IsSerializable)
{
this.Tag =3D node.Tag;
}
if (Nodes !=3D null)
{
if (Nodes.Length > 0)
{
Array.Resize<TreeNodeData>
(ref this.Nodes, node.Nodes.Count + 1);
}
}
}

10 réponses

1 2
Avatar
Jérémy Jeanson
Bonjour Gloops,

Traduction de code Vb vers C#, humm ça me bottes ça ;) (comme quoi Vb on
y passe toujours un jour)

Le code qui contient ton redim peut être contourné en fait car le code
original sert à donner au tableau un taille avant qu'il soit peupler donc :
'Populate the Nodes array with child nodes
ReDim Nodes(treeview.Nodes.Count - 1)
For i As Integer = 0 To treeview.Nodes.Count - 1
Nodes(i) = New TreeNodeData(treeview.Nodes(i))
Next
Peut facilement être remplacé par le code suivant qui résou au passage
ton soucis de null (cas particulier d'une structure, on doit initialiser
tous ses champs dans le constructeur... c# est très strict avec cela et
c'est tant mieux) :

// Check to see if there are any root nodes in the TreeView
if (treeview.Nodes!=null
&& treeview.Nodes.Count == 0)
{
Nodes = null;
return;
}

// Populate the Nodes array with child nodes
Nodes = new TreeNodeData[treeview.Nodes.Count];

for (Int32 i = 0; i < treeview.Nodes.Count; i++)
{
Nodes[i] = new TreeNodeData(treeview.Nodes[i]);
}
Mais si tu utilise .net 3.5 je te conseillerais plutôt un petit bout de
linq pour remplacer tout celà:
public TreeViewData(TreeView treeview)
{
Nodes = treeview.Nodes.Cast<TreeNode>()
.Select(c => new TreeNodeData(c))
.ToArray();
}
C'est tout de même plus propre ;)

Pour ton histoire de node c'est aussi le même genre de choses.

public TreeNodeData(TreeNode node)
{
this.Text = node.Text;
this.ImageIndex = node.ImageIndex;
this.SelectedImageIndex = node.SelectedImageIndex;
this.Checked = node.Checked;
this.Expanded = node.IsExpanded;

this.Tag = (node.Tag != null) &&
node.Tag.GetType().IsSerializable
? node.Tag
: null;

// Check to see if there are any root nodes in the TreeView
if (node.Nodes!=null
&& node.Nodes.Count == 0)
{
this.Nodes = null;
return;
}

// Populate the Nodes array with child nodes
this.Nodes = new TreeNodeData[node.Nodes.Count];

for (Int32 i = 0; i < node.Nodes.Count; i++)
{
this.Nodes[i] = new TreeNodeData(node.Nodes[i]);
}
}

Mais j'aurais toujours une préférence pour le code suivant avec Linq
public TreeNodeData(TreeNode node)
{
this.Text = node.Text;
this.ImageIndex = node.ImageIndex;
this.SelectedImageIndex = node.SelectedImageIndex;
this.Checked = node.Checked;
this.Expanded = node.IsExpanded;

this.Tag = (node.Tag != null) &&
node.Tag.GetType().IsSerializable
? node.Tag
: null;

this.Nodes = node.Nodes.Cast<TreeNode>()
.Select(c => new TreeNodeData(c))
.ToArray();
}

Mais petite question : pourquoi passes tu par ces classes
intermédiaires? je crois que l'on peut très bien sérialisé les donnée du
treeview en passant juste pas les nodes du trieeview ou alors en faisant
par des nodes héritant de treeviewNode et en leur ajoutant l'attribut de
sérialisation...enfin je pense que c'est possible, jamais testé.
--
Jérémy JEANSON
MCP
http://www.jjeanson.fr
Avatar
Gloops
Jérémy Jeanson a écrit, le 18/05/2009 09:10 :

// Check to see if there are any root nodes in the TreeView
if (treeview.Nodes!=null
&& treeview.Nodes.Count == 0)
{
Nodes = null;
return;
}

// Populate the Nodes array with child nodes
Nodes = new TreeNodeData[treeview.Nodes.Count];

for (Int32 i = 0; i < treeview.Nodes.Count; i++)
{
Nodes[i] = new TreeNodeData(treeview.Nodes[i]);
}



En remplaçant (dans TreeNodeData) treeview par node (puisqu'il s'agit d e
la fonction qui gère un nœud) ça marche.

Il reste quand même une erreur signalée deux fois, une fois au débu t de
la fonction et une fois sur return :
Error 2 Field 'XmlIntrospection.TreeViewPersist.TreeNodeData.Tag' must
be fully assigned before control leaves the constructor

Il est vrai que this.Tag = node.Tag se trouve dans une alternative, don c
n'est exécuté que si la condition est vérifiée. ça aurait pu ê tre un
warning, ben non, c'est une erreur, la compilation n'aboutit pas.

Mais si tu utilise .net 3.5 je te conseillerais plutôt un petit bout de
linq pour remplacer tout celà:
public TreeViewData(TreeView treeview)
{
Nodes = treeview.Nodes.Cast<TreeNode>()
.Select(c => new TreeNodeData(c))
.ToArray();
}
C'est tout de même plus propre ;)




Bon, je crois qu'il faut que j'ouvre une sorte de dossier avec tous les
tests qu'il faudra que je me dépêche d'essayer une fois que j'aurai l a
version 3 sous la main (et pour la 3.5) et un peu de temps à consacrer à ça.



Pour ton histoire de node c'est aussi le même genre de choses.

public TreeNodeData(TreeNode node)
{



Ah, on dirait que j'ai anticipé. Mais de toute manière je ne suis pas
encore tout-à-fait au bout, d'ailleurs il reste une (double) erreur à
corriger, pour que le Tag soit considéré comme initialisé.

Mais petite question : pourquoi passes tu par ces classes
intermédiaires? je crois que l'on peut très bien sérialisé les donnée du
treeview en passant juste pas les nodes du trieeview ou alors en faisan t
par des nodes héritant de treeviewNode et en leur ajoutant l'attribut de
sérialisation...enfin je pense que c'est possible, jamais testé.



C'est bien de dire que la classe est sérialisable, mais après il faut
dire comment on sérialise (et désérialise), sinon on se retrouve av ec
une erreur de compilation. Il y a deux méthodes et une propriété à
définir si je me rappelle bien (et gare aux tricheurs, si on ne retourn e
rien alors qu'on doit retourner un nœud, erreur de compilation) et c'es t
précisément à ça que sert la classe intermédiaire : éviter de refaire
tout le boulot à chaque projet.
Avatar
Jérémy Jeanson
Bonjour Gloops,

En utilisant l'instruction
this.Tag = (node.Tag != null) && node.Tag.GetType().IsSerializable
? node.Tag
: null;
Cela ne suffit pas à calmer le compilateur?
Sur mon projet de test je n'ai pas ce soucis.
--
Jérémy JEANSON
MCP
http://www.jjeanson.fr
Avatar
Gloops
Jérémy Jeanson a écrit, le 19/05/2009 08:38 :
Bonjour Gloops,

En utilisant l'instruction
this.Tag = (node.Tag != null) && node.Tag.GetType().IsSerializable
? node.Tag
: null;
Cela ne suffit pas à calmer le compilateur?



Effectivement, là il s'en sort. Il faut être astucieux, quelquefois.

Sur mon projet de test je n'ai pas ce soucis.



Ah ? C'est donc un constructeur d'une public struct TreeNodeData ?
Dans une classe qui dérive de IXmlSerializable ?

Comme références j'ai ça :

using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Windows.Forms;
using System.Xml.Serialization;
using System.Xml;
Avatar
Gloops
Ah, ben du coup, ça va déjà bien mieux, merci, puisque le souci que j'ai
maintenant, c'est que writer.WriteEndDocument n'écrit rien, dans le
fichier de sortie il me manque donc la balise </xml>. Certes une fois
qu'il n'y aura plus que ça je peux le faire en append dans un vulgaire
fichier texte, mais bon, si on peut travailler proprement ...

En dehors de ça j'aimerais bien aller à la ligne à chaque nouvelle
balise et respecter les indentations, mais ça je sais que c'est loin
d'être gagné.
_____________________________________________
Jérémy Jeanson a écrit, le 19/05/2009 08:38 :
Bonjour Gloops,

En utilisant l'instruction
this.Tag = (node.Tag != null) && node.Tag.GetType().IsSerializable
? node.Tag
: null;
Cela ne suffit pas à calmer le compilateur?
Sur mon projet de test je n'ai pas ce soucis.


Avatar
Gloops
Au passage, je note une limite à l'exercice de convertir un TreeView en
XMLDocument et inversement : les mêmes propriétés n'existent pas da ns
les deux, donc il s'agit d'établir une convention de correspondance
entre les deux. Par exemple, le treeview peut faire apparaître une
branche pour chaque attribut d'un nœud. Le nom de l'attribut n'apparaî t
pas nécessairement, auquel cas, forcément il y a perte d'information, ce
qui intrinsèquement n'est pas gênant dans la mesure où il s'agit
seulement d'informations de structure, mais ce qui fait que la
traduction inverse ne pourra faire apparaître les mêmes noms
d'attributs. Si on souhaite que le nom d'attribut apparaisse il convient
d'établir une syntaxe, par exemple le texte de la branche du treeview
pourra faire apparaître le nom de l'attribut suivi d'un double point
puis de sa valeur.

Par voie de conséquence, si un treeview fait apparaître les données d'un
document xml, obtenir le même document à partir du treeview suppose d e
travailler avec la même convention, il convient donc lors de l'écritu re
du programme de sérialisation de tenir compte d'un autre programme avec
lequel on souhaite être compatible pour la désérialisation.

Peut-être peut-on se rendre compte de ça en regardant attentivement u n
treeview et un document xml, mais j'avoue que pour ma part ça n'est
devenu évident qu'en cours de développement.
Avatar
Jérémy Jeanson
Bonjour Gloops,

Je comprend que tu te pose pas mal de question au sujet de la
sérialisation, mais as tu été faire un petit tour dans la MSDN pour voir
tout ce dont regorgeait le namespace System.Xml.Serialization.

C'est assez surprenant de voir que XmlSerializer dispose de bon nombres
de possibilité pour gérer finement un fichier XML mais qu'il est
totalement mésestimé... pas mal de monde pense qu'il ne sert qu'à
sérialiser ou dé-sérialiser un XML qui ne serra lisible que via .net.

Ceci est faut faut et archi faux... enfin ce n'est pas ton sujet, pardon
je m'égards. Regardes bien le XmlSerializer il dispose dans
System.Xml.Serialization d'attributs pouvant être ajouté à une classe
pour manager le comportement de l'objet lors de sa sérialisation.

Par exemple :
pour changer le nom d'un propriété de type énumération lors de sa
sérialisation
[System.Xml.Serialization.XmlArrayItem("Menuitem")]
public ObservableCollection<MyMenuItem> Items
{
get { return myItems; }
}

Changer le nom d'un noeud (donc le nom de la classe sérialisée):
[XmlRoot("Menuitem")]
public class MyMenuItem
{

}

Interdire la sérialisation d'une propriété
[System.Xml.Serialization.XmlIgnore]
public ImageSource Image
{

}

Enfin ce ne sont que des exemples, il y encore bien d'autres choses qui
sont possible et qui peuvent rendre service dans System.Xml.Serialization.

--
Jérémy JEANSON
MCP
http://www.jjeanson.fr
Avatar
Gloops
Bonjour Jérémy,

Oui, j'ai vu qu'il y a pas mal de choses, et que je n'ai probablement
pas fait le tour.

Je vais déjà tâcher d'implémenter ça à peu près proprement au moins une
fois, rien qu'avec le writer il s'agit d'appeler dans le bon ordre
WriteStartDocument, WriteStartElement, WriteStartAttribute, et la suite.

Cela étant, si on passe à côté d'observations simples sur les con trôles
entre lesquels on veut transférer des informations, on risque de
parcourir la doc un bout de temps en oubliant d'avoir les idées claires
sur ce qu'on veut faire.

Bon enfin là d'ici quelques jours je pense avoir un outil pour poser un e
autre question :)

Après, j'espère arriver au bout de cette histoire de sous-état, qui a un
peu tendance à prendre le chou. J'ai éliminé quelques pistes, c'est au
moins déjà ça, mais cette histoire de Dataset qui n'a pas d'instanc e ...

En attendant merci d'avoir éclairé ma lanterne.

_____________________________________________
Jérémy Jeanson a écrit, le 20/05/2009 08:50 :
Bonjour Gloops,

Je comprend que tu te pose pas mal de question au sujet de la
sérialisation, mais as tu été faire un petit tour dans la MSDN po ur voir
tout ce dont regorgeait le namespace System.Xml.Serialization.

C'est assez surprenant de voir que XmlSerializer dispose de bon nombres
de possibilité pour gérer finement un fichier XML mais qu'il est
totalement mésestimé... pas mal de monde pense qu'il ne sert qu'à
sérialiser ou dé-sérialiser un XML qui ne serra lisible que via . net.

Ceci est faut faut et archi faux... enfin ce n'est pas ton sujet, pardo n
je m'égards. Regardes bien le XmlSerializer il dispose dans
System.Xml.Serialization d'attributs pouvant être ajouté à une cl asse
pour manager le comportement de l'objet lors de sa sérialisation.

Par exemple :
pour changer le nom d'un propriété de type énumération lors de sa
sérialisation
[System.Xml.Serialization.XmlArrayItem("Menuitem")]
public ObservableCollection<MyMenuItem> Items
{
get { return myItems; }
}

Changer le nom d'un noeud (donc le nom de la classe sérialisée):
[XmlRoot("Menuitem")]
public class MyMenuItem
{

}

Interdire la sérialisation d'une propriété
[System.Xml.Serialization.XmlIgnore]
public ImageSource Image
{

}

Enfin ce ne sont que des exemples, il y encore bien d'autres choses qui
sont possible et qui peuvent rendre service dans System.Xml.Serializati on.



Avatar
Gloops
Jérémy Jeanson a écrit, le 18/05/2009 09:10 :
// Check to see if there are any root nodes in the TreeView
if (treeview.Nodes!=null
&& treeview.Nodes.Count == 0)
{
Nodes = null;
return;
}

// Populate the Nodes array with child nodes
Nodes = new TreeNodeData[treeview.Nodes.Count];

for (Int32 i = 0; i < treeview.Nodes.Count; i++)
{
Nodes[i] = new TreeNodeData(treeview.Nodes[i]);
}



Ah oui donc finalement on repeuple l'objet depuis le début. ça évit e de
chercher un équivalent à Redim Preserve. C'est vrai que dans le cas
présent on a toujours les infos disponibles dans un autre objet. Sinon
avant d'ajouter un élément il faut sauvegarder les infos dans un obje t
tampon j'imagine ? Enfin, si l'objet n'a pas de méthode Item.Add
Avatar
Gloops
Gloops a écrit, le 19/05/2009 20:34 :
Ah, ben du coup, ça va déjà bien mieux, merci, puisque le souci q ue j'ai
maintenant, c'est que writer.WriteEndDocument n'écrit rien, dans le
fichier de sortie il me manque donc la balise </xml>. Certes une fois
qu'il n'y aura plus que ça je peux le faire en append dans un vulgair e
fichier texte, mais bon, si on peut travailler proprement ...



Bien, maintenant il ne reste plus que ça, mais apparemment cette balise
</xml> n'est pas obligatoire, puisque IE réussit à lire le résultat même
sans. Il y a un autre point sur lequel il faut veiller au grain, c'est
la compatibilité entre le jeu de caractères déclaré et les caract ères
écrits. Par défaut on a UTF-8, et avec ça IE s'arrête au premier
caractère accentué rencontré. Alors il faut mettre ISO-8859-15 à la
place et ça baigne. ça a été vite fait dans le bloc-notes, demain je
regarde comment gérer ça dans le programme.


En dehors de ça j'aimerais bien aller à la ligne à chaque nouvell e
balise et respecter les indentations, mais ça je sais que c'est loin
d'être gagné.



Ah, ça, je me le suis géré à la paluche dans le bloc-notes.
1 2