C Pottinger Ответов: 2

Почему это неявное преобразование незаконно?


Здравствуйте, гуру кодового проекта.

Ранее я написал класс, который был оболочкой вокруг десятичного типа C#. Это позволило мне добавить все виды пользовательских функций, которые мне были нужны. Сейчас я пытаюсь сделать этот класс-оболочку универсальным, но сталкиваюсь с ошибкой компилятора, которую не совсем понимаю...

Супер-упрощенный пример моего кода приведен ниже. Ошибка компилятора, которую я получаю, находится в последней строке кода:
Cannot implicitly convert type 'int' to 'ConsoleApplication1.testing.WrapperForFloat'. An explicit conversion exists (are you missing a cast?)<


Чего я не понимаю, так это почему, когда
int y = testImplied
при обнаружении компилятор знает, что WrapperForFloat наследует
implicit operator int(Wrapper<T> val)
из обертки и компилируется конверсия, но она этого не знает
testImplied = x
следует использовать унаследованный WrapperFloat
implicit operator Wrapper<T>(int val)

Я был бы очень признателен за любое объяснение.

Что я уже пробовал:

namespace ConsoleApplication1
{
    using System;

    namespace testing
    {
        public class Wrapper<T>where T: IConvertible
        {
            private T _value;

            public Wrapper()
            {
                _value = default(T);
            }

            public Wrapper(T intialValue)
            {
                _value = intialValue;
            }

            public static implicit operator Wrapper<T>(int val)
            {
                var x = (T)Convert.ChangeType(val, typeof(T));
                return new Wrapper<T>(x);
            }

            public static implicit operator int(Wrapper<T> val)
            {
                return (int)Convert.ChangeType(val._value, typeof(int));
            }
        }

        public class WrapperForFloat : Wrapper<float>
        {
            public WrapperForFloat() : base() { }
            public WrapperForFloat(float initialval) : base(initialval) { }
        }

        class Program
        {
            static void Main(string[] args)
            {
                var testExplicit = new Wrapper<float>(10f);
                var testImplied = new WrapperForFloat(11f);

                int x = testExplicit;
                int y = testImplied;

                testExplicit = y;
                testImplied = x;
            }
        }
    }
}

2 Ответов

Рейтинг:
9

F-ES Sitecore

testImplied = x 
should use WrapperFloat's inherited 
implicit operator Wrapper<T>(int val) 


С чего бы это? Что оператор выполняет преобразование из int в обертке в<Т>, Вы делаете запрос на преобразование из int в WrapperForFloat. Даже если это сработало, вы не можете перейти от Wrapper<t> К WrapperForFloat

Добавьте это в WrapperForFloat

public static implicit operator WrapperForFloat(int val)
{
    return new WrapperForFloat(val);
}


C Pottinger

Ага. Имеет смысл. Теперь я чувствую себя глупо...

Рейтинг:
17

Dave Kreskowiak

Это не работает, потому что возвращаемый тип-это Wrapper<t>, а не WrapperForFloat.

По сути, вы делаете это:

WrapperForFloat wff = new Wrapper<float>(x);

Это не сработает. Компилятор не будет выполнять неявное понижение от Wrapper<float> До WrapperForFloat для вас.

[редактировать]
Это не работает, потому что класс-оболочка может не реализовывать все методы, предоставляемые классом WrapperForFloat, поэтому вы не можете рассматривать результирующий объект cast как реальный экземпляр WrapperForFloat.
[/редактировать]


Нет никакого хорошего способа обойти это. Видеть эта дискуссия[^] и некоторые возможные обходные пути.


C Pottinger

Спасибо, Дэйв. Иногда вы не можете увидеть лес из-за всех деревьев.