[C#] Petite question

Bonjour,

je souhaite tester le type d’un de mes objets :

[code]switch (monObj[5].Type) // renvoit un type
{
case Type.GetType(« System.Char »):
// code
break;

case Type.GetType("System.Int32"):
// code
break;
//...[/code]

Le souci c’est que le compilo me renvoit une erreur :
« A constant value is expected »

en essayant avec une syntaxe similaire, la même :

[code]switch (monObj[5].Type) // renvoit un type
{
case typeof(char):
// code
break;

case typeof(int):
// code
break;
//...[/code]

du coup j’ai du faire ça :

[code]switch (monObj[5].Type.ToString()) // renvoit une chaine
{
case « System.Char »:
// code
break;

case "System.Int32":
// code
break;
//...[/code]

Mais bon c’est vraiment moche :crying:
C’était juste en attendant de faire mieux, mais je voulais savoir surtout pourquoi j’avais une erreur, sachant que ce que je passe en paramètre est bien une constante non ?

Merci :slight_smile:

Ce qu’il n’aime pas c’est ça : case typeof(char):
Le compilo s’attend à toujours avoir quelque chose qui ne changera pas, donc pas d’appel de méthode/propriété/variable. Uniquement des const (readonly peut-être aussi, me souviens plus).

La raison est que le compilateur doit absolument vérifier que 2 étiquettes n’ont pas la même valeur. Or, cette vérification n’est pas possible si des variables sont utilisées. Comme il n’y a pas la possibilité de déclarer une méthode comme déterministe fonction de ses paramètres, tu ne peux pas utiliser typeof().

Un “if / else if” pourrait remplacer ton switch.

Le switch c’est le mal :slight_smile:

[quote=« Styx31, post:2, topic: 36571 »]Ce qu’il n’aime pas c’est ça : case typeof(char):
Le compilo s’attend à toujours avoir quelque chose qui ne changera pas, donc pas d’appel de méthode/propriété/variable. Uniquement des const (readonly peut-être aussi, me souviens plus).

La raison est que le compilateur doit absolument vérifier que 2 étiquettes n’ont pas la même valeur. Or, cette vérification n’est pas possible si des variables sont utilisées. Comme il n’y a pas la possibilité de déclarer une méthode comme déterministe fonction de ses paramètres, tu ne peux pas utiliser typeof().

Un « if / else if » pourrait remplacer ton switch.[/quote]

Ok, je pensais que ça aurait réagi comme une constante mais non…

Ah ? Je ne savais pas. Je l’utilise quand j’ai pas mal de cas à tester. Bon je m’en passerai dorénavant alors :crying:)

Merci :cry:)

Nan, mais c’est pas le mal absolu, ca c’est le goto :slight_smile: mais ca reste une instruction a utiliser avec precaution, et parcimonie.

Le switch pour une variable sur un ensemble fini, au cardinal « relativement » petit (typiquement une enum) a l’avantage de raler a la compilation, si on a oublié un cas.

Mais… « précaution et parcimonie », c’est une bonne approche. :crying:

[quote=« LodeRunner, post:6, topic: 36571 »]Le switch pour une variable sur un ensemble fini, au cardinal « relativement » petit (typiquement une enum) a l’avantage de raler a la compilation, si on a oublié un cas.

Mais… « précaution et parcimonie », c’est une bonne approche. :crying:[/quote]

Oui je ne l’utilise que dans ce cas là :slight_smile:

Mais le probleme là c’est qu’il y a pas de typage dynamique sur le switch non ? A la compilation il a besoin de savoir quel est le type de l’objet qu’il va prendre en paramettre d’où l’obligation de faire un ToString…

Mais pourquoi il peut pas prendre un type Type ?

le problème du switch (je ne dis pas que c’est le cas ici), c’est que dans la grande majorité des cas, il cache une faiblesse de design (objet du moins).
C’est même un cas d’école de refactoring en fait: souvent on peut remplacer un switch par un bon polymorphisme des familles. Ce n’est pas juste pour la beauté du geste, mais pour le principe de responsabilité unique, expliciter les concepts plutôt que de les cacher dans les méthodes, et éviter la duplication de comportement.

[quote=« BodySplash, post:9, topic: 36571 »]le problème du switch (je ne dis pas que c’est le cas ici), c’est que dans la grande majorité des cas, il cache une faiblesse de design (objet du moins).
C’est même un cas d’école de refactoring en fait: souvent on peut remplacer un switch par un bon polymorphisme des familles. Ce n’est pas juste pour la beauté du geste, mais pour le principe de responsabilité unique, expliciter les concepts plutôt que de les cacher dans les méthodes, et éviter la duplication de comportement.[/quote]

C’est complètement le cas ici et ça fera sans doute l’objet d’un autre post d’ici demain ou après demain. J’avais besoin d’un code qui compile, je reverrai cette partie ce soir.

(Ez, démasqué :slight_smile: )

A vue de nez (et avant d’avoir pris mon chocolat matinal), ça doit être parce que quand tu rentres dans le domaine des generics créés programmatiquement, ou des assemblies chargées dynamiquement, tu peux commencer à rencontrer au runtime des types que le compilateur ne connaissait pas du tout au moment où il a compilé le switch. Donc du coup c’est plus des valeurs constantes, compilationnellement parlant (oui j’invente des mots le matin).

Un switch sur un type dans ce genre c’est deja super moche a la base, ca sent le polymorphisme qu’on a oublié ou le design boiteux… Switch c’est fait pour faire sur des constantes et des value types, deja un switch sur une string, c’est sympa parfois pour hacker un truc rapidos mais dans du code de production moi en regle generale je l’accepte trop pas dans un code review.

C’est vrai que t’es chef maintenant :slight_smile:

Wouaow ! :cry:

Bon… pour virer ce switch de $£’!§ il faut que j’explique ce que je veux faire exactement.

En fait je veux tout simplement charger des données d’un fichier csv dans une DataTable. Et j’ai la définition des colonnes de ce fichier comme ceci :

NOM_DE_LA_PREMIERE type (longueur) NOM_DE_LA_DEUXIEME type (longueur) NOM_DE_LA_TROISIEME type (longueur)

le paramètre longueur est optionnel.

je stocke ces informations dans un objet MyColumn :

public class MyColumn { public string Name { get; set; } public Type Type { get; set; } }

Un autre objet nommé MyObj contient (entre autre) un tableau de MyColumn :

public class MyObj { public MifColumn[] MifColumns { get; set; } }

Maintenant que ça c’est fait, je veux charger le contenu de mon fichier csv dans un DataTable. Le type des DataColumns de la DataTable seraient définis par le type de MyColumn.

DataTable dataTable = new DataTable(); dataTable.Columns.AddRange(GetMyColumns(myObj));

il ne me reste plus qu’à remplir ma DataTable :

[code]while ((line = reader.ReadLine()) != null)
{
string[] lineParts = line.Split(’,’);
DataRow newRow = dataTable.NewRow();

for (int i = 0; i < dataTable.Columns.Count; i++)
{
	switch (Type.GetTypeCode(mifDoc.MifColumns[i].Type))
	{
		case TypeCode.String:
			newRow[i] = Convert.ToString(lineParts[i].Trim('"'), CultureInfo.InvariantCulture);
			break;
		case TypeCode.Int32:
			newRow[i] = Convert.ToInt32(lineParts[i], NumberFormatInfo.InvariantInfo);
			break;
		case TypeCode.Int16:
			newRow[i] = Convert.ToInt16(lineParts[i], NumberFormatInfo.InvariantInfo);
			break;
		case TypeCode.Decimal:
			newRow[i] = Convert.ToDecimal(lineParts[i], NumberFormatInfo.InvariantInfo);
			break;
		case TypeCode.Single:
			newRow[i] = Convert.ToSingle(lineParts[i], NumberFormatInfo.InvariantInfo);
			break;
		case TypeCode.DateTime:
			newRow[i] = Convert.ToDateTime(lineParts[i].Trim('"'), NumberFormatInfo.InvariantInfo);
			break;
		case TypeCode.Boolean:
			newRow[i] = Convert.ToBoolean(lineParts[i], NumberFormatInfo.InvariantInfo);
			break;
		default:
			break;
	}
}
dataTable.Rows.Add(newRow); 

}[/code]

et donc pour remplacer le switch j’avais pensé à faire quelque chose du genre :

[code]while ((line = reader.ReadLine()) != null)
{
string[] lineParts = line.Split(’,’);
DataRow newRow = dataTable.NewRow();

for (int i = 0; i < dataTable.Columns.Count; i++)
{
// A la manière de Array.ConvertAll()
newRow[i] = MyConvert<string,T>(lineParts[i],MyObj.MyColumns[i].Type);
}
dataTable.Rows.Add(newRow); 

}[/code]

Ou un truc du genre mais là je ne vois pas comment implémenter « MyConvert » :crying:(

Hehe non chef c’est du boulot :crying: En vrai je suis juste assez senior pour pouvoir accepter ou pas des trucs dans des codes review de codeurs moins seniors hehe.

Bon j’y connais rien du tout a C# mais bon.

Pourquoi tu fais pas des classes fille de MyColumn qui redefinisse le type à chaque fois, comme ça si t’as un tableau où tu peux manger des classes filles avec en te servant de l’hériatage…

Ouep, ça va se terminer comme ça :slight_smile: