2011-12-15 8 views
2

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

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

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 вместо моей структуры и имеет такое же точное поведение, так что, очевидно, это ожидаемое поведение, но я думал, что явное приведение, что приводит к терять данные будут бросать исключение.

+0

Нет, явные приведения типов могут потерять информацию. Неявные броски не должны. –

+0

Собираетесь ли вы с помощью 'AnyCPU',' x32' или 'x64'? – ja72

+0

@ ja72 Извините за задержку в ответе, но я компилирую с x86 – psubsee2003

ответ

7

Когда компилятор анализирует явную пользователем определенного преобразование допускается поместить явный встроенный преобразования на «обе стороны» (или оба) преобразования. Так, например, если у вас есть определенный пользователь преобразование INT Фреды, и у вас есть:

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

то причины компилятора «существует явное преобразование INT Фред, так что я могу сделать явное преобразование из int в int, а затем преобразование int в Fred.

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

То же самое относится к неявным преобразованиям, компилятор может вставлять встроенные неявные преобразования на e итерационной части пользовательского неявного преобразования.

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

Правильное построение собственных явных преобразований - сложная задача на 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

+0

Спасибо за объяснение и ссылки на ваш блог. Я пропустил некоторые из старых сообщений, так что это было очень информативно. Проект, над которым я работаю, - это своего рода проект для домашних животных, который я использую так же, чтобы экспериментировать с новыми аспектами, которые я использую, чтобы помочь в моей реальной работе, поэтому явные/неявные преобразования - это как эксперимент, так и все. – psubsee2003

+0

И теперь, когда я прочитал ваш блог, я думаю, что я понимаю ловушки выполнения пользовательских явных и неявных преобразований. Из вашего ответа я понимаю, что существует явное преобразование между long и byte, компилятор вставляет это преобразование в вызов метода для преобразования из long в байт в Parameter. И так как приведение от длинного к байту будет принимать наименее значимые 8 бит из длинного, я остаюсь с 146 как значение, назначенное параметру. Большое спасибо, спасибо. – psubsee2003

3

Эта цель:

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

И этот код:

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

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

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

+0

@Hank Я не был достаточно ясен в описании типа безопасности, который я искал. Существует несколько различных типов параметров (для аргументов, Parameter1, Parameter2 и т. Д.). Тип безопасности, который я искал, - это предотвращение случайного использования параметра Parameter1 в методе, который ищет параметр Parameter2. Но ваш смысл имеет смысл независимо, поэтому я переосмыслию неявный подход оператора. – psubsee2003

 Смежные вопросы

  • Нет связанных вопросов^_^