Явный и неявный оператор с числовыми типами и неожиданными результатами - PullRequest
2 голосов
/ 16 декабря 2011

Я никогда не делал обширной работы с операторами перегрузки, особенно с неявными и явными преобразованиями.

Однако у меня есть несколько числовых параметров, которые часто используются, поэтому я создаю структуру как оболочку вокругчисловой тип, чтобы строго ввести эти параметры.Вот пример реализации:

public struct Parameter
{
    private Byte _value;
    public Byte Value { get { return _value; } }

    public Parameter(Byte value)
    {
        _value = value;
    }

    // other methods (GetHashCode, Equals, ToString, etc)

    public static implicit operator Byte(Parameter value)
    {
        return value._value;
    }
    public static implicit operator Parameter(Byte value)
    {
        return new Parameter(value);
    }

    public static explicit operator Int16(Parameter value)
    {
        return value._value;
    }
    public static explicit operator Parameter(Int16 value)
    {
        return new Parameter((Byte)value);
    }
}

Поскольку я экспериментировал с моей тестовой реализацией, чтобы освоить явные и неявные операторы, я попытался явно привести Int64 к моему типу Parameter и кя удивился, что это не бросило исключение, и что еще более удивительно, он просто усек число и пошел дальше.Я попытался исключить пользовательский явный оператор, и он по-прежнему вел себя так же.

public void TestCast()
{
    try
    {
        var i = 12000000146;
        var p = (Parameter)i;
        var d = (Double)p;

        Console.WriteLine(i);   //Writes 12000000146
        Console.WriteLine(p);   //Writes 146
        Console.WriteLine(d);   //Writes 146
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);  //Code not reached
    }
}

Итак, я повторил свой эксперимент с простой Byte вместо моей структуры и с таким же точным поведением, так что, очевидно, это ожидаемое поведение, но я думал, что явное приведение, которое приводит к потереданных выдаст исключение.

Ответы [ 2 ]

7 голосов
/ 16 декабря 2011

Когда компилятор анализирует явное определяемое пользователем преобразование , разрешается помещать явное встроенное преобразование на "любую сторону" (или оба) преобразования. Так, например, если у вас есть пользовательское преобразование из int в Fred, и у вас есть:

int? x = whatever;
Fred f = (Fred)x;

тогда компилятор рассуждает «есть явное преобразование из int в Fred, поэтому я могу сделать явное преобразование из int? В int, а затем преобразовать int в Fred.

В вашем примере есть встроенное явное преобразование из длинного в короткое, и есть определенное пользователем явное преобразование из короткого в Параметр, поэтому преобразование длинного в Параметр допустимо.

То же самое верно для неявных преобразований; компилятор может вставлять встроенные неявные преобразования по обе стороны от пользовательского неявного преобразования.

Компилятор никогда не связывает два определенных пользователем преобразования .

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

Информацию о некоторых интересных аспектах цепных преобразований см. В моих статьях на эту тему:

http://blogs.msdn.com/b/ericlippert/archive/2007/04/16/chained-user-defined-explicit-conversions-in-c.aspx

http://blogs.msdn.com/b/ericlippert/archive/2007/04/18/chained-user-defined-explicit-conversions-in-c-part-two.aspx

3 голосов
/ 16 декабря 2011

Эта цель:

, поэтому я создаю структуру в качестве оболочки для числового типа, чтобы строго ввести эти параметры

И этот код:

public static implicit operator Byte(Parameter value)
{
    return value._value;
}
public static implicit operator Parameter(Byte value)
{
    return new Parameter(value);
}

находятся в полном противоречии.Добавляя двусторонние неявные операторы, вы отменяете любую безопасность типов, которую может принести оболочка.

Так что отбросьте неявные преобразования.Вы можете изменить их на явные.

...