3 votes

Le transfert d'un objet avec un opérateur de conversion échoue.

Donc j'ai cet objet, disons DoubleContainer.

public struct DoubleContainer
{
    private readonly double _value;

    private DoubleContainer(double value)
    {
        _value = value;
    }

    public static implicit operator double(DoubleContainer doubleContainer)
    {
        return doubleContainer._value;
    }

    public static DoubleContainer Create(double value)
    {
        return new DoubleContainer(value);
    }
}

Le mouler fonctionne comme prévu dans presque tous les cas, sauf lorsqu'il est passé dans une fonction en tant qu'objet.

Le code suivant génère une InvalidCastException si je passe dans un DoubleContainer :

public double GetDouble(Object input)
{
    return (double)input;
}

J'arrive à le faire fonctionner si j'utilise la dynamique :

public double GetDouble(Object input)
{
   return (double)(dynamic)input;
}

Mon problème avec cette solution est que Visual Studio grise le (dynamic), parce qu'il devrait être redondant, donc quelqu'un pourrait le supprimer. Je ne sais pas non plus s'il y a d'autres endroits dans la base de code où ce même problème peut se produire.

Y a-t-il quelque chose que je puisse faire à mon implémentation de DoubleContainer pour que ma première implémentation de GetDouble() fonctionne ? J'ai essayé d'ajouter un autre opérateur de conversion implicite d'Object à DoubleContainer, mais "les conversions définies par l'utilisateur vers ou depuis une classe de base ne sont pas autorisées".....

3voto

Evk Points 17804

Vous ne pouvez pas faire en sorte que cela fonctionne, car vous ne pouvez que débloquer une structure en boîte (c'est ce que vous faites avec (double) input ) au type exact non fictif, pour les raisons les mieux décrites dans cette article par Eric Lippert. Donc à chaque fois que vous faites (double) someObject - cela ne fonctionnera que si l'objet est effectivement un double pas int pas float pas DoubleContainer . Si vous vous attendez à d'autres types - vous pouvez mieux utiliser Convert.ToDouble . Pour que cela fonctionne avec votre type, il faut qu'il implémente IConvertible :

public struct DoubleContainer : IConvertible
{
    private readonly double _value;

    private DoubleContainer(double value)
    {
        _value = value;
    }

    public static implicit operator double(DoubleContainer doubleContainer)
    {
        return doubleContainer._value;
    }

    public static DoubleContainer Create(double value)
    {
        return new DoubleContainer(value);
    }

    public double ToDouble(IFormatProvider provider) {
        return _value;
    }

    public bool ToBoolean(IFormatProvider provider) {
        // delegate to your double
        return ((IConvertible) _value).ToBoolean(provider);
    }

    // ... rest is skipped ...

Ensuite, il fonctionnera avec

public double GetDouble(Object input)
{
    return Convert.ToDouble(input);
}

1voto

Gian Paolo Points 3362

Lors de la conversion d'un objet en double, le compilateur ne sait pas qu'il doit faire appel à votre code existant. operator double Il n'y aura donc pas d'appel à votre double opérateur défini par l'utilisateur.

Lorsque vous insérez dynamic au milieu, le compilateur va générer quelque chose comme "si cette référence a un opérateur double, appelez-le", donc ça marche.

Donc, cela ne peut pas fonctionner tant que vous lancez un System.Object à un double, alors que le code suggéré par @juharr, légèrement modifié, fonctionnera :

public double GetDouble(Object input)
{
    if (input is DoubleContainer)
    {
        var dc = (DoubleContainer)input; 
        return (double)dc;
    }
    return (double)input;
}

EDIT : code modifié selon le commentaire de @SergiyKlimkov

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X