2009-03-18 4 views
4

HI!C#: Comment utiliser l'opérateur de distribution implicite lors de la conversion d'un objet en un type?

Voici mon cas: J'ai un type de valeur qui est enveloppé dans un autre type avec des convertisseurs implicites appropriés. Si je jette un type enveloppé à un objet, puis que j'essaie d'obtenir la valeur d'origine, je peux le faire en cast en deux étapes seulement. Si simplifié mon code est le suivant:

public enum MyEnum : int 
    { 
     First, 
     Second 
    } 


    public class Test<T> 
    { 
     public Test(T val) 
     { 
      Value = val; 
     } 

     private T Value { get; set; } 


     public static implicit operator T(Test<T> m) 
     { 
      return m.Value; 
     } 

     public static implicit operator Test<T>(T m) 
     { 
      var res = new Test<T>(m); 
      return res; 
     } 
    } 


    static void Main() 
    { 
     object res = new Test<MyEnum>(MyEnum.First); 
     Console.WriteLine((MyEnum)(Test<MyEnum>)res); 
     Console.WriteLine((MyEnum)res); 
    } 

Première "Console.WriteLine" fonctionne bien. Le deuxième échoue.

Est-il possible de modifier ce comportement et de le faire fonctionner sans double diffusion?

MISE À JOUR 1

Je dois utiliser l'objet à la valeur (dans l'application réelle, je dois jeter des biens ComboBox.SelectedItem et je ne veux pas ajouter la propriété supplémentaire pour ComboBox, parce que je vais devoir changer mon code d'interaction UI partout).

MISE À JOUR 2

conversions implicites vers et à partir System.Object ne sont pas autorisés.

MISE À JOUR 3

Mis à jour mon exemple de code pour refléter tout le problème.

Répondre

4

Si vous souhaitez simplifier la diffusion et ne pas prendre en charge l'effet de performance, créez une méthode d'extension.

public static T To<T>(this object obj) { 
    Type type = obj.GetType(); 
    MethodInfo[] methods = type.GetMethods(BindingFlags.Public | BindingFlags.Static); 
    MethodInfo method = methods.FirstOrDefault(mi => (mi.Name == "op_Implicit" || mi.Name == "op_Explicit") && mi.ReturnType == typeof(T)); 
    if (method == null) 
     throw new ArgumentException(); 
    return (T)method.Invoke(null, new[] { obj }); 
} 

Utilisation

Console.WriteLine(res.To<MyEnum>()); 
+0

C'est ce que j'ai trouvé moi-même - Extender Merci, je vais le marquer comme réponse. –

6

N'utilisez pas object de cette façon. Écrivez votre première ligne comme ceci:

Test res = new Test(1); 

Si vous devez avoir dans un premier objet, rappelez-vous que tout le compilateur le sait à ce stade est que c'est un objet, et rien de plus. Vous, en tant que programmeur, avez des informations supplémentaires sur ce que vous attendez de cet objet, mais pour que le compilateur tire parti de cette information, vous devez le mettre dans votre code quelque part.

Mise à jour:
Je suis content d'avoir pu trouver cette fois, parce que cet article presque très rapide par Eric Lippert, qui travaille sur la conception du langage C#, a ce matin et explique le problème en profondeur:
http://blogs.msdn.com/ericlippert/archive/2009/03/19/representation-and-identity.aspx

+0

J'ai ajouté une mise à jour qui explique pourquoi je ne peux pas le faire. –

1

ou même

var res = new Test(1); 
+0

J'ai ajouté une mise à jour qui explique pourquoi je ne peux pas le faire. –

1

Votre résolution variable locale est toujours objet de type; donc la ligne qui ne fonctionne pas essaie de convertir un objet, ce n'est pas un int, en un int, ce qui ne peut pas être fait. Même que cela ne fonctionne pas:

 object d = 5.5d; 
     Console.WriteLine((int)d); 

EDIT:

Peut-être un modèle qui pourrait aider est quelque chose comme ceci:

 if (res.GetType() == typeof(Test)) 
     { 
      Console.WriteLine((int)(Test)res); 
     } 
     else 
     { 
      Console.WriteLine((int)res); 
     } 

Il est une solution très localisée à votre problème, mais peut-être cela fonctionnera pour toi.

+0

Exactement. Y a-t-il un moyen de contrôler cela? –

+0

Que voulez-vous dire par contrôle? –

+0

Faites de la magie pour que cela fonctionne :) Console.WriteLine ((int) (double) d); - sans la * double * partie? –

0

Bien que l'erreur est due à res étant de type objet, je ferais le test-> opérateur int explicite ...

+0

ne fonctionne pas non plus :( –

2

Au lieu d'ajouter les opérateurs implicites, d'envisager d'utiliser IConvertible. Vous avez seulement besoin d'implémenter la méthode ToInt32, les autres n'ont aucun sens et vous pouvez lancer InvalidCastException dans les autres méthodes. Ensuite, vous pouvez utiliser la méthode Convert.ToInt32() pour convertir votre objet en une seule étape.

+0

Désolé de ne pas spécifier ma tâche entièrement.En fait, je travaille avec Enums et mon emballage est générique.Je ne peux pas utiliser IConvertible –

+0

Code mis à jour de manière appropriée –

Questions connexes