J'ai construit un système de types personnalisé à utiliser dans les scripts C# dans une application. Les scripts sont compilés à la volée et permettent l'interaction avec les données internes de l'application. Ce type de système est conçu de manière abstraite en utilisant des interfaces comme IValue
. Mise en œuvre de IValue
peut être un RefString
, RefInteger
, RefDouble
(parmi beaucoup d'autres, mais c'est suffisant pour démontrer mon problème).Abstraction empêchant l'utilisation de types personnalisés, quelles sont les règles à suivre dans une implémentation?
Maintenant, nous arrivons au point où je suis coincé ... L'utilisation de ces objets IValue
est quelque peu artificielle. Il est considéré comme une bonne conception de toujours utiliser les interfaces pour interagir avec les objets mais il n'y a aucune possibilité de définir une conversion implicite ou une surcharge d'un opérateur pour des interfaces. Cela cède à des situations où la distribution explicite laide est inévitable pour que le bon opérateur soit utilisé.
Exemple:
IValue Add(IValue a, IValue b)
{
//return a+b; // won't work: which operator +() to use?
return (RefInteger)a + (RefInteger)b;
}
Dans le cas de C# dans les expressions impliquant des types de valeur, les conversions implicites sont fournis. Quel est un bon moyen de concevoir un tel système personnalisé?
J'ai réécrit le système de types en supprimant l'interface IValue
et en introduisant une classe de base RefValue
. De cette façon, une partie des distributions explicites pourrait déjà être éliminée. J'ai implémenté une partie de la surcharge de l'opérateur dans cette classe de base mais cela a causé beaucoup de problèmes avec les opérateurs de conversion par défaut ... La logique à implémenter dans l'implémentation de l'opérateur implique beaucoup de connaissances sur les types du système. Je pense que c'est en quelque sorte toujours la voie à suivre, mais quelles sont les règles à suivre, pour mettre en œuvre cela de manière correcte et sûre?
EDIT: Après avoir lutté un certain temps, certaines des règles je pourrais savoir sont:
- Déclare implicites que les opérateurs de conversion de types de base (int, double, chaîne, ...) Déclarer explicitement les conversions aux types de base (pour éviter les conversions implicites à int !! ce qui arrive assez souvent, mais pourquoi?)
- Pour éviter les appels ambigus, les opérateurs +, -, /, * ne doivent pas être écrasés dans la classe de base et dans les classes dérivées. [Quel est le chemin à parcourir alors? Je l'ai fait l'opération de surcharge dans les classes dérivées, cela nécessite la coulée sur l'utilisation, ce qui est à nouveau laid ...]
J'ai encore des problèmes avec la conversion de type par défaut si je fais un 'iValue b = 6; par exemple. Cela ne peut pas être déclaré dans l'interface et fonctionne si j'ai un opérateur de conversion implicite dans la classe 'RefInteger'.L'idée d'impliquer des génériques peut peut-être me sauver de quelques ennuis, merci pour l'indice. Les opérateurs comme +, *, /, - ne peuvent pas être déclarés dans les interfaces, ou ai-je oublié quelque chose? – jdehaan
@jdehaan: Non, autant que je sache, il n'y a aucun moyen de déclarer les opérateurs dans une interface. –
J'ai tourné ma conception sur l'utilisation d'une classe concrète en utilisant quelques conversions implicites permises et en forçant des moulages pour d'autres de la même manière que la promotion numérique dans la norme ECMA 334. Cela semble au moins privider un bon code lisible et répondre aux exigences de conversion de type. Merci pour votre aide, j'ai accepté votre réponse à la fin vous aviez raison dans le sens qu'il n'y a pas de manière optionnelle de le résoudre au niveau de l'interface. – jdehaan