1

Hello,

Est-ce que vous savez comment s'appelle ce composant ?

AkQw

Accessoirement, est-il disponible par défaut dans Visual Studio Express 2008 (je ne l'ai pas trouvé), ou bien est-il possible de l'obtenir quelque part, ou bien rien de tout ça ?

Merci ^^
avatar
All right. Keep doing whatever it is you think you're doing.
------------------------------------------
Besoin d'aide sur le site ? Essayez par ici :)

2

PropertyGrid, tout simplement smile
avatar
Zeroblog

« Tout homme porte sur l'épaule gauche un singe et, sur l'épaule droite, un perroquet. » — Jean Cocteau
« Moi je cherche plus de logique non plus. C'est surement pour cela que j'apprécie les Ataris, ils sont aussi logiques que moi ! » — GT Turbo

3

Ah oui, je suis une bille, merci grin

(pour ma défense il n'est que dans la liste "Tous les Windows Form" donc il fallait quand même connaître son nom ^^)

[edit] ah merde il fonctionne par réflexion sur un objet, pas moyen de définir dynamiquement les champs et leur type on dirait... donc ça ne correspond pas à ce dont j'ai besoin :/
avatar
All right. Keep doing whatever it is you think you're doing.
------------------------------------------
Besoin d'aide sur le site ? Essayez par ici :)

4

ICustomTypeDescriptor est ton ami.
Et selon ce que tu veux faire il y a des moyens plus élégants: voir TypeDescriptor, TypeDescriptionProviderAttribute, et Type Descriptor Overview
Sinon pense aussi à DisplayNameAttribute et DescriptionAttribute, ce sont des éléments assez basiques mais presques indispensables.
Si avec ça tu ne trouves pas ton bonheur...
avatar
Le scénario de notre univers a été rédigée par un bataillon de singes savants. Tout s'explique enfin.
T'as un problème ? Tu veux un bonbon ?
[CrystalMPQ] C# MPQ Library/Tools - [CrystalBoy] C# GB Emulator - [Monoxide] C# OSX library - M68k Opcodes

5

top mci ^^
avatar
All right. Keep doing whatever it is you think you're doing.
------------------------------------------
Besoin d'aide sur le site ? Essayez par ici :)

6

il y a une raison pour laquelle la méthode "SetValue" héritée de "PropertyDescriptor" reçoit toujours un argument "value" de type String ? j'ai pourtant retourné le type qui m'intéresse depuis la méthode "PropertyType", et "GetValue" fournit des résultats de ce même type... il semble y avoir une conversion automatique effectuée via "ToString();" mais du coup je perds toutes les informations de mon objet :/
avatar
All right. Keep doing whatever it is you think you're doing.
------------------------------------------
Besoin d'aide sur le site ? Essayez par ici :)

7

Je ne me souviens pas avoir rencontré ce types de problèmes. A mon avis, ça doît être lié à la conversion de types.
Tu pourrais donner un exemple plus précis de ton problème ? (Par exemple quel type d'objet pose ce problème)
(Sinon si je cherche dans mes archives de code je dois pouvoir trouver un truc qui marche si ça t'intéresse ^^)
avatar
Le scénario de notre univers a été rédigée par un bataillon de singes savants. Tout s'explique enfin.
T'as un problème ? Tu veux un bonbon ?
[CrystalMPQ] C# MPQ Library/Tools - [CrystalBoy] C# GB Emulator - [Monoxide] C# OSX library - M68k Opcodes

8

Alors je voudrais ajouter dynamiquement une propriété à un objet A, et cette propriété doit apparaître dans le PropertyGrid comme une valeur à choisir parmi une liste définie.

- J'ai un objet "ListValue" utilisé comme valeur de ma propriété. Il contient une valeur (numérique) et un descriptif (string). Il surcharge la méthode "ToString" qui fait un simple "return this.desc", j'espérais comme ça afficher le descriptif mais conserver la valeur numérique.

- J'ai un objet "ListTypeConverter" qui hérite de "TypeConverter" et surcharge les méthodes "GetStandardValuesSupported", "GetStandardValuesExclusive" et "GetStandardValues" pour définir la liste des choix possibles. Il retourne une collection de type "TypeConverter.StandardValuesCollection" remplie avec des objets de type "ListValue".

- J'ai un objet "ListPropertyDescriptor" qui hérite de "PropertyDescriptor", il s'agit donc de ma propriété. Il possède un "TypeConverterAttribute" instancié avec "ListTypeConverter" parmi ses attributs pour prendre en compte le fait qu'il s'agisse d'une liste de choix. Son accesseur "PropertyType" retourne "typeof (ListValue)", et sa méthode "GetValue" retourne la valeur courante de type "ListValue" également.

- Enfin, j'ai mon objet "A" qui contient une "PropertyDescriptorCollection" pour contenir ses propriétés, parmi lesquelles se trouvent une instance de "ListPropertyDescriptor".

Visuellement j'obtiens bien le résultat voulu (ça), mais si je choisis un élément dans la liste (supposée être une liste de "ListValue" si je ne me plante pas) ça m'appelle la méthode "SetValue" de la classe "ListPropertyDescriptor" en passant en paramètre une valeur de type "String" (le texte correspondant au choix que j'ai sélectionné, par exemple "Choix #2") au lieu de mon objet "ListValue" d'origine. Du coup je ne peux plus rien en faire, c'est sa valeur qui m'intéresse et non pas sa description textuelle.

J'ai vu qu'on peut utiliser les TypeConverters pour convertir les données au moment de l'affichage et effectuer une conversion inverse au moment de la sélection, mais ça fait deux traitements supplémentaires dont je ne vois pas l'intérêt. On ne peut pas tout simplement continuer à manipuler le type initial tout le temps ?
avatar
All right. Keep doing whatever it is you think you're doing.
------------------------------------------
Besoin d'aide sur le site ? Essayez par ici :)

9

Est-ce que tu as bien implémenté les fonctions de conversion ?
De mémoire la valeur risque effectivement d'être convertie en string pour affichage, et l'affectation se passera avec une valeur de type string.
L'implémentation par défaut appelle juste ToString(), mais il revient à toi de permettre la conversion inverse, et/ou de faire une meilleure conversion vers le type string, pour que l'utilisateur puisse taper ses propres valeurs dans le champ et qu'elles soient reconnues, ou non ^^
avatar
Le scénario de notre univers a été rédigée par un bataillon de singes savants. Tout s'explique enfin.
T'as un problème ? Tu veux un bonbon ?
[CrystalMPQ] C# MPQ Library/Tools - [CrystalBoy] C# GB Emulator - [Monoxide] C# OSX library - M68k Opcodes

10

Tu parles de ConvertFrom et ConvertTo ? Justement non puisque je ne veux jamais convertir mais plutôt garder mon type personnalisé, de la même façon que ce qu'on peut faire avec les éléments d'une ComboBox par exemple (ToString() est utilisé à l'affichage, mais le reste du temps on manipule un objet quelconque).
avatar
All right. Keep doing whatever it is you think you're doing.
------------------------------------------
Besoin d'aide sur le site ? Essayez par ici :)

11

Hmm et bien il faudrait probablement que tu t'occupes de ces méthodes, tout au moins ConvertFrom (string).
L'opération ne devrait pas te poser trop de problèmes si ton ensemble de valeurs standard est fixe: un simple Dictionary<string, ListValue> te permettra de donner le change. Dans le sens inverse, si ton ToString() est fiable, pas besoin d'implémenter la conversion :d
Après, ce n'est pas le seul moyen d'affecter des options dans un PropertyGrid (vive UITypeEditor) mais en fait utiliser un convertisseur de type est l'opération de base qui permet de convertir l'entrée du textbox (qui est de type String) dans le PropertyGrid en autre chose. Après il y a différentes variantes, qui affichent, soit rien, soit une liste de valeurs standard, soit une liste des propriétés contenues par l'objet, mais il te faudra gérer la conversion si tu t'aventures par là. (A moins que j'aie oublié un détail, parce que ça fait quand même un certain temps que je n'ai pas touché à ça ^^)
avatar
Le scénario de notre univers a été rédigée par un bataillon de singes savants. Tout s'explique enfin.
T'as un problème ? Tu veux un bonbon ?
[CrystalMPQ] C# MPQ Library/Tools - [CrystalBoy] C# GB Emulator - [Monoxide] C# OSX library - M68k Opcodes

12

Ok donc je suis obligé d'avoir une conversion... Pour le coup ConvertFrom est inutile, je peux très bien faire ma conversion inverse dans la fonction "SetValue" mais ça implique un lookup dans une table pour retrouver une valeur que je suis pourtant censé déjà connaître.

Vraiment pas top comme fonctionnement pour le coup :/
avatar
All right. Keep doing whatever it is you think you're doing.
------------------------------------------
Besoin d'aide sur le site ? Essayez par ici :)

13

Bon, faute de mieux je suis parti sur la solution du ./12

Par contre j'ai un autre problème (ouééé grin) : je cherche à faire quelque chose que je ne sais pas comment réaliser en C# (en C++ ça prendrait 3 lignes, mais là...)

J'aurais besoin de créer un objet, disons "Modifier", qui prenne en paramètre une référence vers une variable (ou un attribut) et qui soit capable par la suite de modifier cette variable. Le détail c'est que par "modifier" je ne parle pas d'appeler ses méthodes et autres, mais bien de remplacer la valeur de la variable. Le problème c'est que pour ça il me faut conserver une référence vers la variable en question, mais que le mot-clé "ref" du C# se limite aux paramètres des fonctions. Certes il y a bien des pointeurs, mais c'est "unsafe" et j'ai cru comprendre qu'il fallait prendre pas mal de précautions pour éviter que la CLR ne modifie les adresses lors d'un passage du GC.

Voilà idéalement comment j'aimerais que la classe s'utilise :

http://www.mirari.fr/g4iY

En C++ ça serait très facile : il suffirait que "myRef" soit de type "T&" et qu'il soit initialisé dans le constructeur de "Modifier". Mais en C# la seule solution que j'ai trouvée consiste à passer à "Modifier" non pas une référence vers la variable mais deux delegates (un setter et un getter). Ça marche très bien mais ça m'oblige à déclarer deux méthodes pour chaque variable que je veux "Modifier"-er (voilà ce que ça donne) : très lourd.

Y-a-t'il moyen de faire autrement ?

Merci smile
avatar
All right. Keep doing whatever it is you think you're doing.
------------------------------------------
Besoin d'aide sur le site ? Essayez par ici :)

14

Zephyr (./13) :
Le problème c'est que pour ça il me faut conserver une référence vers la variable en question, mais que le mot-clé "ref" du C# se limite aux paramètres des fonctions.
J'étais tombé sur exactement le même problème, et après recherche sur le net, apparemment il n'existe pas d'équivalent .NET aux pointeurs sur les objets sad (l'explication étant que ce serait incompatible avec la méthode utilisée pour gérer le cycle de vie des objets, si je me souviens bien).

Y'a effectivement moyen de bidouiller avec du code unsafe, mais c'est crade.
avatar
Zeroblog

« Tout homme porte sur l'épaule gauche un singe et, sur l'épaule droite, un perroquet. » — Jean Cocteau
« Moi je cherche plus de logique non plus. C'est surement pour cela que j'apprécie les Ataris, ils sont aussi logiques que moi ! » — GT Turbo

15

Zephyr (./13) :
Bon, faute de mieux je suis parti sur la solution du ./12
Oué enfin pour le coup ton SetValue n'est pas sensé accepter un string (ça devrait générer une exception de cast) alors que le ConvertFrom si, donc ça serait plus propre de l'utiliser smile
J'aurais besoin de créer un objet, disons "Modifier", qui prenne en paramètre une référence vers une variable (ou un attribut) et qui soit capable par la suite de modifier cette variable. Le détail c'est que par "modifier" je ne parle pas d'appeler ses méthodes et autres, mais bien de remplacer la valeur de la variable. Le problème c'est que pour ça il me faut conserver une référence vers la variable en question, mais que le mot-clé "ref" du C# se limite aux paramètres des fonctions.

Ce qui est parfaitement normal sachant que
[ol][li]Une référence est un pointeur[/li]
[li]Tu ne sais pas sur quoi pointe un pointeur: Est-ce que c'est un champ d'une classe ou bien une variable locale d'une fonction[/li][/ol]
Certes il y a bien des pointeurs, mais c'est "unsafe" et j'ai cru comprendre qu'il fallait prendre pas mal de précautions pour éviter que la CLR ne modifie les adresses lors d'un passage du GC.
Ce truc s'appelle le pinning (je laisse aux lecteurs le loisir de traduire en fr) et en C# c'est pas bien compliqué, ça se fait avec un petit coup de fixed( ... ) {}, et en dehors de ça, le code usafe fonctionne très bien avec des paramètres de sécurité normaux, il faut juste éviter de l'utiliser quand ce n'est pas nécessaire.
En C++ ça serait très facile : il suffirait que "myRef" soit de type "T&" et qu'il soit initialisé dans le constructeur de "Modifier". Mais en C# la seule solution que j'ai trouvée consiste à passer à "Modifier" non pas une référence vers la variable mais deux delegates (un setter et un getter). Ça marche très bien mais ça m'oblige à déclarer deux méthodes pour chaque variable que je veux "Modifier"-er (voilà ce que ça donne) : très lourd.
Y-a-t'il moyen de faire autrement ?
Fais toi un listing des façons différentes accéder à une valeur dans un type en C#... Tu t'apercevras que la liste n'est pas si longue que ça.
Après la méthode la meilleure dépend de ce que tu veux faire précisément, mais celle que tu as trouvé est la moins couteuse au niveau mémoire je pense.
Après tu peux envisager d'utiliser des propriétés ou des méthodes Dynamiques pour éviter de devoir créer explicitement ces méthodes get/set... Mais je crois que ça s'arrête la...
Pour le reste si tu veux vraiment une référence tu devras utiliser un type référence (genre Boxed<T>) et je pense que c'est tout tongue
avatar
Le scénario de notre univers a été rédigée par un bataillon de singes savants. Tout s'explique enfin.
T'as un problème ? Tu veux un bonbon ?
[CrystalMPQ] C# MPQ Library/Tools - [CrystalBoy] C# GB Emulator - [Monoxide] C# OSX library - M68k Opcodes

16

Sinon y'a ca :

public class PropertyModifier
{
    object toModify;

    public PropertyModifier(object toModify)
    {
        this.toModify = toModify;
    }

    public void Modify(string property, object value)
    {
        FieldInfo fi = this.toModify.GetType().GetField(property, BindingFlags.Instance | BindingFlags.NonPublic);
        if (fi != null && fi.FieldType == value.GetType())
            fi.SetValue(this.toModify, value);
    }
}
avatar
Webmaster et développeur du site. Pour tout probleme ou question envoyez un mini message ou mail.

Suivez l'actualité de tous vos site préférés sur yAronews : http://ns.yaronet.com =)

17

le fait de chercher une propriété à partir d'une chaine qui contient son nom est pas top je trouve (je savais même pas que c'était possible tellement c'est aux antipodes de l'optimisation ^^), mais par contre c'est une solution qui a le mérite de laisser la classe initiale intacte donc je vais ptet partir là dessus, mci happy
avatar
All right. Keep doing whatever it is you think you're doing.
------------------------------------------
Besoin d'aide sur le site ? Essayez par ici :)

18

ça pour le coup par contre c'est une des solutions parmi les moins efficaces grin
La rélexion ça fonctionne avec le type object donc boxing obligatoire pour les types valeurs (donc allocation de mémoire à chaque appel), plus recherche des membres pas très rapides. La méthode des delegate est clairement plus efficace. Celà étant dit si tu utilises des propriétés comme je l'ai suggéré plus haut (sachant que les propriétés auto-générées existent avec C# 3.0, pas besoin de taper le code du get et du set si tu n'en as pas envie) tu peux t'en tirer à bien meilleur compte: (reste peut être des erreurs de syntaxe)
sealed class Modifier<T>
{
	delegate T GetTDelegate();
	delegate void SetTDelegate(T value);

	GetTDelegate get;
	SetTDelegate set;

	public Modifier(object obj, PropertyInfo property)
	{
		if (!(property.CanRead && property.CanWrite))
			throw new InvalidOperationException();
		get = (GetTDelegate)Delegate.CreateDelegate(typeof(GetTDelegate), obj, property.GetGetMethod());
		set = (SetTDelegate)Delegate.CreateDelegate(typeof(GetTDelegate), obj, property.GetSetMethod());
	}

	public T Get()
	{
		return get();
	}

	public void Set(T value)
	{
		set(value);
	}
}


Le niveau au dessus étant les méthodes dynamiques et là tu peux t'en tirer avec des champs directement (c'est mon approche préférée mais un peu plus complexe à mettre en place, et un peu moins efficace point de vue mémoire)
avatar
Le scénario de notre univers a été rédigée par un bataillon de singes savants. Tout s'explique enfin.
T'as un problème ? Tu veux un bonbon ?
[CrystalMPQ] C# MPQ Library/Tools - [CrystalBoy] C# GB Emulator - [Monoxide] C# OSX library - M68k Opcodes

19

C'est quoi l'intérêt d'une propriété auto-générée ? C'est idiot, autant mettre l'attribut public directement ^^

Sinon vu qu'il manque l'autre classe je ne suis pas sûr de saisir le fonctionnement de ta méthode : elle permet d'utiliser les deux accesseurs d'un attribut plutôt que les deux fonctions que je définissais au ./12 ? Si oui, ça revient rigoureusement au même :/ (à moins qu'il n'y ait pas besoin de définir ces propriétés)
avatar
All right. Keep doing whatever it is you think you're doing.
------------------------------------------
Besoin d'aide sur le site ? Essayez par ici :)

20

Une propriété autogénérée c'est une propriété où les accesseurs get/set sont générés automatiquement tongue
Si tu n'as pas besoin d'avoir accès à la variable sous-jacente tu déclares une propriété comme ça: int MaVariable { get; set; }
Ce truc te crée automatiquement un champ privé et des accesseurs qui vont bien, et si plus tard ça te va pas il suffit de changer l'implémentation de la propriété, mais en attendant ça te fait toujours moins de code à taper. cheeky
(Celà dit personellement je préfère toujours déclarer mes propriétés moi même mais c'est quand même une fonctionnalité bien sympa)

A savoir bien sur que dans le code (CIL) généré, une propriété "X" lecture/écriture possède une méthode get_X(); et une méthode set_X(value); pour représenter ses accesseurs, du coup oui tu les utilises comme ce que tu faisais précédemment, sauf que tu n'as pas à déclarer de fonction explicitement smile

Sinon je peux te montrer l'approche DynamicMethod qui crée dynamiquement le get/set mais qui est un peu plus lourde à l'initialisation (et aussi rapide pour le reste du temps), mais quoi qu'il en soit ça sera toujours mieux que de la réflexion pure. (Enfin le code qu'a posté yAro peut être un peu optimisé quand même, notamment avec des TypedReference ^^)
avatar
Le scénario de notre univers a été rédigée par un bataillon de singes savants. Tout s'explique enfin.
T'as un problème ? Tu veux un bonbon ?
[CrystalMPQ] C# MPQ Library/Tools - [CrystalBoy] C# GB Emulator - [Monoxide] C# OSX library - M68k Opcodes

21

GoldenCrystal (./20) :
Une propriété autogénérée c'est une propriété où les accesseurs get/set sont générés automatiquement tongue

Donc en gros tu dis ".Length est la propriété liée à l'attribut .length" et il te crée automatiquement les get/set par défaut (ceux qui renvoient/modifient directement l'attribut sans pré/post traitement) ? Si c'est ça c'est vraiment inutile, créer des propriétés n'a plus aucun sens et autant tout mettre en public directement ^^

Sinon pour ta solution ça me fait remplacer l'écriture de 2 méthodes par l'écriture d'une propriété. Certes c'est un petit gain, mais ça m'oblige quand même à ajouter du code dans la classe dont je veux modifier les attributs donc c'est toujours pas terrible :/
Sinon je peux te montrer l'approche DynamicMethod qui crée dynamiquement le get/set mais qui est un peu plus lourde à l'initialisation (et aussi rapide pour le reste du temps), mais quoi qu'il en soit ça sera toujours mieux que de la réflexion pure. (Enfin le code qu'a posté yAro peut être un peu optimisé quand même, notamment avec des TypedReference ^^)

Oh bah si t'as ça sous la main envoie, je sais pas si je l'utiliserai mais par curiosité ça m'intéresse quand même ^^
avatar
All right. Keep doing whatever it is you think you're doing.
------------------------------------------
Besoin d'aide sur le site ? Essayez par ici :)

22

Les TypedReference ne sont pas CLS compliant ... on peut aussi directement injeter de l'IL tant qu'a faire cheeky
avatar
Webmaster et développeur du site. Pour tout probleme ou question envoyez un mini message ou mail.

Suivez l'actualité de tous vos site préférés sur yAronews : http://ns.yaronet.com =)

23

Zephyr (./21) :
GoldenCrystal (./20) :
Une propriété autogénérée c'est une propriété où les accesseurs get/set sont générés automatiquement tongue
Donc en gros tu dis ".Length est la propriété liée à l'attribut .length" et il te crée automatiquement les get/set par défaut (ceux qui renvoient/modifient directement l'attribut sans pré/post traitement) ?
Plus exactement tu lui dis juste je veux une propriété "Length" avec un get et un set (oui sans un set elle te sert a rien cheeky ) et il crée en interne un champ associé (auquel tu ne peux pas accéder) + get/set par défaut qui font rien (ce qui ne t'empêche en rien d'en faire plus tard une vraie propriété si le besoin s'en ressent)
Si c'est ça c'est vraiment inutile, créer des propriétés n'a plus aucun sens et autant tout mettre en public directement ^^

Bah non ça encapsule quand même ton champ, et je te rappelle que tu peux avoir des modificateurs d'accès différents sur le get et le set, et que ta propriété n'a aucune obligation d'être publique, donc c'est pas si limité que ça (utilisé de cette façon, c'est surtout un truc pour flemmards, mais ça a l'avantage de te masquer le champ utilisé en interne, ce qui peut être utile si jamais tu ne veux pas y avoir accès)
Sinon je peux te montrer l'approche DynamicMethod qui crée dynamiquement le get/set mais qui est un peu plus lourde à l'initialisation (et aussi rapide pour le reste du temps), mais quoi qu'il en soit ça sera toujours mieux que de la réflexion pure. (Enfin le code qu'a posté yAro peut être un peu optimisé quand même, notamment avec des TypedReference ^^)

Oh bah si t'as ça sous la main envoie, je sais pas si je l'utiliserai mais par curiosité ça m'intéresse quand même ^^
Heu, donc voilà la solution la plus polyvalente: tromb Fichier joint : FieldModifier.zip
C'est tout bidon mais à l'heure actuelle je pense qu'on ne peut pas faire plus efficace (Il faut garder à l'esprit que tout ça fonctionne sans aucun bidouillage de mémoire et que tout est parfaitement géré par le Garbage Collector)
avatar
Le scénario de notre univers a été rédigée par un bataillon de singes savants. Tout s'explique enfin.
T'as un problème ? Tu veux un bonbon ?
[CrystalMPQ] C# MPQ Library/Tools - [CrystalBoy] C# GB Emulator - [Monoxide] C# OSX library - M68k Opcodes

24

GoldenCrystal (./23) :
Plus exactement tu lui dis juste je veux une propriété "Length" avec un get et un set (oui sans un set elle te sert a rien cheeky ) et il crée en interne un champ associé (auquel tu ne peux pas accéder) + get/set par défaut qui font rien (ce qui ne t'empêche en rien d'en faire plus tard une vraie propriété si le besoin s'en ressent)

Heu... oui, pour le coup je vois toujours pas l'intérêt mais surtout je suis même pas sûr d'avoir compris ta phrase grin
Bah non ça encapsule quand même ton champ, et je te rappelle que tu peux avoir des modificateurs d'accès différents sur le get et le set, et que ta propriété n'a aucune obligation d'être publique, donc bah voilà quoi tongue

Ce que je veux dire c'est que si c'est juste pour dire "mon code est propre, tous mes attributs sont privés" et qu'à coté de ça t'as des propriétés auto-générées qui permettent d'y accéder directement, ça revient à avoir oublié "légèrement" ses cours de POO et l'intérêt même de l'encapsulation ^^
Bon, ok donc voilà la solution la plus polyvalente: tromb Fichier joint : FieldModifier.zipC'est tout bidon mais à l'heure actuelle je pense qu'on ne peut pas faire plus efficace (Il faut garder à l'esprit que tout ça fonctionne sans aucun bidouillage de mémoire et que tout est parfaitement géré par le Garbage Collector)

Okay, c'est pas si compliqué que ça finalement (par contre c'est ignoble, particulièrement la génération dynamique de méthodes, alors que le besoin à la base ne me semblait pas si tordu que ça... le C# n'est pas si puissant que ça en fait :/). Par contre je me demande un truc : par rapport à la solution de yAro qui consisterait à récupérer le FieldInfo et le modifier via ".SetValue", ça apporte quoi ? C'est plus rapide ? (parcequ'à l'initialisation du modifier vous faites exactement la même chose)
avatar
All right. Keep doing whatever it is you think you're doing.
------------------------------------------
Besoin d'aide sur le site ? Essayez par ici :)

25

Disons que récupérer le FieldInfo a un coût non négligeable (donc déjà tu peux le stocker pour ne le faire qu'une fois), et ensuite accéder aux valeurs avec GetValue et SetValue, force une opération de boxing pour les types valeurs (par exemple int -> object ça alloue donc un objet sur le tas de type "int", il faudra qu'il soit collecté plus tard), et ça fait énormément de vérifications à chaque fois car il ne peut apporter aucune fiabilité à ce que tu lui passes en paramètre: Est-ce l'objet est bien du bon type ? Est-ce que ta valeur est bien du bon type ? A quel endroit en mémoire est-ce que je dois stocker la valeur ? Comment je convertis l'a valeur vers le type destination ? Est-ce que c'est un type valeur ou référence ? Etc...
Avec une méthode en revanche, qu'elle soit dynamique ou non, la vérification n'est faite qu'une seule fois, à la compilation JIT (et éventuellement une autre fois avant par le compilateur du langage afin de générer du code valide). Dans ce cas précis, tu n'as aucune inconnue au problème, pas de type object qui cache une valeur inconnue de type inconnu dont la fiabilité n'est pas assurée... Du coup ça te fait un code généré très simple et très direct dont le coût est à peu de choses prêt le cout d'un appel à une méthode virtuelle.
J'ai la flemme de faire un benchmark pour tester, mais ça ne me choquerait en aucun cas que la différence de performance entre l'un et l'autre soit d'un facteur 10 ou plus wink
avatar
Le scénario de notre univers a été rédigée par un bataillon de singes savants. Tout s'explique enfin.
T'as un problème ? Tu veux un bonbon ?
[CrystalMPQ] C# MPQ Library/Tools - [CrystalBoy] C# GB Emulator - [Monoxide] C# OSX library - M68k Opcodes

26

Oki, je pensais pas que le boxing était aussi couteux, par contre le FieldInfo il n'a jamais été question de faire autrement que le stocker une seule fois ^^ Dommage d'ailleurs que la récupération d'un champ passe par son nom, sinon ça aurait permis de déplacer le GetField à l'intérieur de la classe Modifier et de rendre ça réellement transparent :/

[edit] au fait, les TypedReferences ne peuvent pas être des attributs de classe => inutilisable ^^
avatar
All right. Keep doing whatever it is you think you're doing.
------------------------------------------
Besoin d'aide sur le site ? Essayez par ici :)

27

Bon voilà, je viens d'utiliser ta solution GoldenCrystal, et ça marche impec top (l'ILGenerator c'est vachement pratique en fait, j'y avais jamais touché mais je sens que vais pas tarder à me pencher dessus ^^)

J'ai juste déplacé le GetField à l'intérieur de "Modifier" pour masquer (presque) complètement le mécanisme, du coup la construction d'un modifieur ressemble à "new Modifier<String> (this, "myField")". L'idéal serait de passer en paramètre l'attribut myField plutôt qu'une chaine contenant son nom, de façon à ce que ce soit réellement transparent et surtout que la spécialisation du Modifier<String> soit automatiquement connue par inférence de type (de façon à pouvoir écrire "new Modifier (this, this.myField)") mais je ne sais pas si on peut obtenir le nom d'un champ à partir de l'une de ses instances.

Sinon du coup je retourne au problème du post ./6, à savoir que ma PropertyGrid n'arrive pas à manipuler un type quelconque sans le transformer en chaine de caractère, et cette fois je ne peux pas tricher avec un dictionnaire vu que je suis dans un cas où la relation chaine<->instance n'est plus bijective (il peut arriver que deux instances différentes donnent le même .ToString ()), je vais regarder si c'est possible de m'en sortir...

Merci beaucoup pour votre aide à tous les deux en tout cas smile
avatar
All right. Keep doing whatever it is you think you're doing.
------------------------------------------
Besoin d'aide sur le site ? Essayez par ici :)

28

Bon en fait je suis un boulet : un TypeConverter fonctionne avec des strings parceque c'est précisément ce pourquoi il est fait. J'avais simplement mal compris son fonctionnement. Des fois que ça puisse servir à d'autres :

- On utilise un TypeConverter pour une propriété qu'on veut pouvoir modifier "inline" en tapant directement une chaine de caractères dans la cellule de la PropertyGrid. Le but est de définir des méthodes de conversion capables de transformer l'objet manipulé en string (pour afficher la valeur courante) et inversement (pour modifier la valeur à partir de la chaine saisie par l'utilisateur).

- Pour proposer à l'utilisateur de choisir un objet quelconque parmi une liste, il faut construire un éditeur capable d'afficher les objets du type en question et de proposer à l'utilisateur d'en choisir (ou saisir) un. Ce n'est plus un TypeConverter qu'il faut utiliser (vu qu'il n'y a aucune conversion, on manipule toujours un type d'objet donné) mais un UITypeEditor (qu'on spécifiera dans les attributs de la propriété via un EditorAttribute).
avatar
All right. Keep doing whatever it is you think you're doing.
------------------------------------------
Besoin d'aide sur le site ? Essayez par ici :)

29

Hmm, fais attention, une simple chaîne de caractères ne permet pas d'identifier un membre de manière suffisamment claire et précise, et tu perds la possibilité d'affiner la description de ce que tu recherches comme ça ^^
(Particulièrement, je ne suis plus certain que ça te permette (par exemple) d'obtenir les membres privés si tu ne lui demandes pas explicitement, mais tu t'en rendras vite compte si ce n'est pas le cas.)

Et oui le TypeConverter est fait pour convertir, mais pas nécéssairement (ou pas uniquement) de ou vers le type string, même si c'est l'utilisation principale qu'on en fait. (Surtout que c'est une interface assez moche à utiliser et que pour le code perso on peut faire mieux et/ou plus simple)
Mais bon, a priori l'utilisateur aurait fait son choix dans les valeurs affichées de type chaîne, et si ton programme n'est pas capable de les discerner, je ne vois pas comment l'utilisateur lui-même aurait pu faire la différence entre elles de toutes façons. cheeky

Sinon juste une petite note annexe, fais bien attention à ce que tu utilises quand tu codes, car les fonctionnalités "avancées" de C# et/ou du CLR peuvent restreintes plus ou moins fortement par des paramètres de sécurité. (Qui empêcheraient l'utilisation de code unsafe ou limiteraient la réflexion aux membres publics par exemple)
ça ne gênera pas si tu code pour toi même ou pour n'importe quel utilisateur maître de sa machine, mais en dehors de ça il faut tenir compte des paramètres de sécurité, et de leur fonctionnement. (Personellement, j'ai toujours du mal à comprendre le fonctionnement de la sécurité .NET, mais il faut au moins savoir qu'elle est là ^^)
avatar
Le scénario de notre univers a été rédigée par un bataillon de singes savants. Tout s'explique enfin.
T'as un problème ? Tu veux un bonbon ?
[CrystalMPQ] C# MPQ Library/Tools - [CrystalBoy] C# GB Emulator - [Monoxide] C# OSX library - M68k Opcodes

30

GoldenCrystal (./29) :
Hmm, fais attention, une simple chaîne de caractères ne permet pas d'identifier un membre de manière suffisamment claire et précise, et tu perds la possibilité d'affiner la description de ce que tu recherches comme ça ^^(Particulièrement, je ne suis plus certain que ça te permette (par exemple) d'obtenir les membres privés si tu ne lui demandes pas explicitement, mais tu t'en rendras vite compte si ce n'est pas le cas.)

Je sais bien, mais si pour conserver l'exhaustivité des possibilités je suis obligé de rendre apparents ces horribles appels à "GetField" je préfère encore ma solution actuelle (a priori je sais ce que je fais, donc quand je recherche un champ via son nom je sais exactement à quoi je veux accéder). Sinon oui j'ai inclus les champs privés dans la recherche, d'ailleurs je vais peut-être n'inclure que ceux-là.
Sinon juste une petite note annexe, fais bien attention à ce que tu utilises quand tu codes, car les fonctionnalités "avancées" de C# et/ou du CLR peuvent restreintes plus ou moins fortement par des paramètres de sécurité. (Qui empêcheraient l'utilisation de code unsafe ou limiteraient la réflexion aux membres publics par exemple)ça ne gênera pas si tu code pour toi même ou pour n'importe quel utilisateur maître de sa machine, mais en dehors de ça il faut tenir compte des paramètres de sécurité, et de leur fonctionnement. (Personellement, j'ai toujours du mal à comprendre le fonctionnement de la sécurité .NET, mais il faut au moins savoir qu'elle est là ^^)

Yep, j'en ai déjà fait les frais avec une sombre histoire d'application qui se retrouvait amputée de pas mal de fonctionnalités quand elle était exécutée depuis un disque réseau ^^
avatar
All right. Keep doing whatever it is you think you're doing.
------------------------------------------
Besoin d'aide sur le site ? Essayez par ici :)