Méthode générique pour la conversion de type
Je suis en train d'écrire générique de la méthode de jeter types. Je veux écrire quelque chose comme Cast.To<Type>(variable)
au lieu de (Type) variable
.
Ma mauvaise version de cette méthode:
public class Cast
{
public static T To<T>(object o)
{
return (T) o;
}
}
Et c'est simple test:
public class A
{
public static explicit operator B(A a)
{
return new B();
}
}
public class B
{
}
A a = new A();
B b = Cast.To<B>(a);
Comme vous l'avez deviné, ce code va échouer avec InvalidCastException
.
Est ce code d'échec à cause de la machine virtuelle ne sais pas comment faire pour lancer une variable de type object
de type B
au moment de l'exécution? Mais le message de l'exception, dit: "impossible de convertir l'objet de type A, de type B". Donc CLR connaît vrai type de la variable o
, pourquoi il ne peut pas effectuer de casting?
Et voici la question principale: comment dois-je réécrire la méthode T To<T>(object o)
pour résoudre ce problème?
- Je n'aime pas vraiment l'idée d'un "convertir quoi que ce soit dans un T". Je suppose que je ne connais pas assez bien le C#.
- Et voici ma question principale: Pourquoi? En quoi est
Cast.To<B>(...)
plus facile à utiliser que(B)...
? - JeffN825 explique - méthode fait couramment à l'interface de style d'appel possible. Je ne vois pas d'autres raisons que moi-même...
- ne vous méprenez pas sur la question, je ne cherche pas à remplacer le traditionnel type de jette, je veux comprendre comment CLR fonctionne et comment résoudre le problème décrit.
- Ah, si c'est juste une question de mieux comprendre le CLR, je peux les comprendre.
Vous devez vous connecter pour publier un commentaire.
Si vous pouvez utiliser c# 4.0 cela fonctionne:
dynamic
fais ici?Tout ce qui a été dit à propos de l'opérateur de résolution est correcte...mais c'est ma réponse à votre question principale:
La clé ici est que la coulée o dynamique de la force de l' .NET pour la recherche explicite de l'opérateur au moment de l'exécution.
Plus, pourquoi ne pas en faire une méthode d'extension?
Au lieu de
vous pouvez faire
Un avantage supplémentaire de l'exposer comme une extension de la méthode est que, vous acquérez une interface fluide pour une conversion explicite (si vous aimez ce genre de chose). J'ai toujours détesté le montant de la parenthèse imbriquée équilibrage requis pour une conversion explicite dans .NET.
De sorte que vous pouvez faire:
au lieu de
qui, pour moi, semble plus claire.
dynamic
ici! Il n'est pas exagéré, c'est EXAGÉRÉ :))a.To<B>()
. Mais la méthode extensions sont point discutable et l'application de celles deobject
type n'est pas une bonne idée.Vous pouvez faire ce truc, trouver les bonnes méthodes à travers la Réflexion:
Dans .NET 4.0, vous pouvez utiliser
dynamic
mot-clé comme suggéré dans d'autres réponses.double d = 1.5; int i = Cast.To<int>(d);
. Ceci ne fonctionnera pas avec InvalidCastException.Votre
Cast.To<T>()
est juste d'essayer d'interpréter la référence à l'objet donné en référence à T. Qui tombe en panne en cours.Et si le compilateur rencontre
(B) a
et sait quea
est de typeA
et le typeA
a au moment de la compilation opérateur de conversion de typeB
- il émet de cette distribution. Ce n'est pas votre cas.Instance
a
est un objet au moment de la coulée deB
. PasA
type, maisobject
. Ainsi, il est impossible de jeterobject
àB
en raison de CLR ne pouvez pas savoir, queo
contient explicite de l'opérateur.EDIT:
Ouais! Voici la solution:
Maintenant CLR sait, que
o
est une instance de typeA
et peut appeler l'explicite de l'opérateur.object
àB
. Siobject
variable contient l'instance deB
. Il est impossible de déterminer s'il est nécessaire pour appeler à la conversion explicite de la méthode de jeter donnéobject
àB
- c'est vrai.A
et pasobject
.Cannot convert type 'T2' to 'T1'
. C'est parce que l'opérateur de résolution de surcharge se produit au moment de la compilation et lorsque leCast
classe est compilée,T1
est seulementobject
et donc ne parvient toujours pas à ramasser le convertisseur.B
à partir de la valeur d'un autre type. Et ne pas appeler opérateur de cast.T2
a le bon opérateur nécessaire pour effectuer la conversion.where
clauses (where T2 : A where T1 : B
) toujours n'autorise pas la distribution. Il doit y avoir quelques petites règles à propos de ce genre de chose dans le langage C# spec. Eric ou Jon, où êtes-vous? 😉dynamic
type n'est pas garante de corriger des choses 🙂Vous ne serez jamais obtenir que cela fonctionne sans un "convertisseur de type'(un processus manuel de la cartographie à travers les attributs pour tous les types connus qui ne sera tout simplement pas se produire). Vous ne peut tout simplement pas juste lancer un non-liées à la classe de béton à l'autre. Il serait briser le modèle d'héritage simple (qui est celui de la définition des principes de la programmation orientée objet - lire sur "le Diamant Problème")
Il a également été noté sur les interfaces (polymorphisme) - les deux classes de dériver à partir de la même interface (qui est dans le même sens)
TypeConverter
? L'OP t ont un type d'utilisateur opérateur de conversion enregistrés. Si vous avez réellement direSystem.ComponentModel.TypeConverter
qui semble à côté de la question que c'est la question de la langue, pas une API en question.TypeConverter
a été mentionné ici, car de principe plutôt qu'en raison de la mise en œuvre concrète. Vous devriez vraiment avoir une telle classe, si vous avez besoin de convertir des classes à partir de différentes parties de la hiérarchie de classe. DoncTypeConverter
point semble correct pour moi.IConvertible
ouTypeConverter
ou de la coutume "convertisseur de type" ne sera pas une mauvaise idée.En fait, j'ai rencontré ce problème plusieurs fois et qu'il n'a pas l'impression de la programmation orientée objet "sale" quand je peux me limiter à des types de mise en œuvre de la
IConvertible
interface. Ensuite, la solution devient réellement très propre!!J'ai utilisé une variante de cela, lorsque j'ai par exemple écrit un générateur de jetons, où l'entrée est une chaîne, mais où les jetons pourrait être interprété comme les deux chaînes de caractères, entiers, et en double.
Puisque c'est à l'aide de la
Convert
classe, le compilateur va effectivement avoir des renseignements pour savoir quoi faire. Ce n'est pas seulement un simple cast.Si vous avez besoin d'encore plus de façon générique de casting, je me demande si ce n'est pas plutôt un problème de conception dans le code. Je pense à un problème avec l'élargissement de la portée de ces choses, c'est que les zones plus vous essayez de couvrir, le plus il sera difficile pour un étranger de savoir combien la méthode peut faire.
Je pense qu'il est de la plus haute importance que le casting fonctionne vraiment quand quelqu'un écrit de façon explicite une méthode de travail afin d'éviter une situation comme
Add(x, y)
que pour certaines valeurs dex
ety
.Je pense que l'attente est différente si vous essayez de la coulée de vous-même, comme dans
T1 x = (T1) T2 y
. Ensuite, je pense que c'est plus apparente que vous êtes vraiment sur votre propre, puisque vous venez de faire quelques fonte plutôt qu'une "couverture de toutes les distributions de la méthode".Dans ce cas, il est clair que c'est précisément affaire à des objets de mise en œuvre
IConvertible
et le développeur peut supposer qu'il marchera bien avec l'un de ces objets.Peut-être orientée objet-philosophie lourds réponse que tout le monde ne sera même d'accord avec, mais je pense que ces sortes de "questions d'ordre conceptuel" finissent souvent dans la philosophie de programmation.
Peut-être pas ce que tu dois faire exactement, mais qui fonctionne:
Mais bien, une telle méthode semble inutile pour moi...
public static T1 To<T1, T2> (T2 o) { return (T1) o; }
A a = new A (); B b = Cast.To<A, B> (a);
. Il fonctionne, mais il est inutile.sourceType
àtargetType
existe parce que les usages pourrait être pas encore écrit. Et il dit (copie&coller à partir du réel compilateur): "Impossible de convertir le type 'sourceType" à "targetType'". Période.