none
Операции преобразования типа RRS feed

  • Вопрос

  • Привет Всем!!!
    Не могу никак полностью разобраться как преобразуются типы с помощью операции преобразования
    Вопрос: Мог бы кто-нибудь объяснить в заданном примере преобразутся ли тип у имени экземпляра класса Demo
    или при передачи этого имени в параметр операции преобразования преобразуется только параметр( т.е Monster x)?
    Немного не понятно как это происходит!!!

    Если преобразуется тип  имени экземпляра класса Demo(при описании выражения double c = Demo;
    , то тогда почему когда происходит явное преобразование(explicit) при описании выражения Demo = (Monster)12;
    мы имя экземпляра Demo которое уже имеет другой тип(double) присваиваем к числу 12 и преобразуем это число к типу Monster? Как то не понятно!!!

    Кто сможет объясните!!!

     

     

    namespace ConsoleApplication141
    {
    
        class Monster
        {
            double len;
    
            public Monster(double d)
            {
                len = d;
            }
    
    
            public static implicit operator double(Monster x)
            {
                return x.len;
            }
    
            public static explicit operator Monster(double v)
            {
                return new Monster(v);
            
            }
        
        }
    
    
        class Program
        {
            static void Main()
            {
                Monster Demo = new Monster(3);
                double c = Demo;
                Console.WriteLine(c);
    
                Demo = (Monster)12;
                Console.WriteLine(Demo);
    
                
    
            }
        }
    }
    • Перемещено I.Vorontsov 21 января 2010 г. 17:21 (От:Visual C#)
    • Перемещено SachinW 1 октября 2010 г. 22:18 MSDN Forums Consolidation (От:Начинающие разработчики)
    19 января 2010 г. 12:43

Ответы

  • Любая операция преобразования - это просто синтаксическое выражение. На самом деле под приведением типов скрывается вызов методов. Когда вы определяете пользовательский оператор приведения, то в действительности вы определяете метод, в котором как параметр передается экземпляр одного типа, а возвращаемым значением является объект преобразованного типа. Реализуя операцию
    double x = Demo; вы на самом деле делаете вызов метода double x = Monster.op_Implicit(Demo);

    Вот как определяются методы приведения в MSIL для вашего случая
    .method public hidebysig specialname static 
            float64  op_Implicit(class Test.Monster x) cil managed
    {
      // Code size       12 (0xc)
      .maxstack  1
      .locals init ([0] float64 CS$1$0000)
      IL_0000:  nop
      IL_0001:  ldarg.0
      IL_0002:  ldfld      float64 Test.Monster::len
      IL_0007:  stloc.0
      IL_0008:  br.s       IL_000a
      IL_000a:  ldloc.0
      IL_000b:  ret
    } // end of method Monster::op_Implicit
    
    .method public hidebysig specialname static 
            class Test.Monster  op_Explicit(float64 v) cil managed
    {
      // Code size       12 (0xc)
      .maxstack  2
      .locals init ([0] class Test.Monster CS$1$0000)
      IL_0000:  nop
      IL_0001:  ldarg.0
      IL_0002:  newobj     instance void Test.Monster::.ctor(float64)
      IL_0007:  stloc.0
      IL_0008:  br.s       IL_000a
      IL_000a:  ldloc.0
      IL_000b:  ret
    } // end of method Monster::op_Explicit
    
    
    
    
    Мы видим, что это обычные статические методы типа
    static double f1(Monster obj)
    static Monster f2(double x),
    правда со специальными именами и прямой вызов их из кода запрещен
    Вот вызовы этих методов в программе при преобразовании типов
    IL_000f:  stloc.0
      IL_0010:  ldloc.0
      IL_0011:  call       float64 Test.Monster::op_Implicit(class Test.Monster)
      IL_0016:  conv.r8
      IL_0017:  stloc.1
      IL_0018:  ldloc.1
      IL_0019:  call       void [mscorlib]System.Console::WriteLine(float64)
      IL_001e:  nop
      IL_001f:  ldc.r8     12.
      IL_0028:  call       class Test.Monster Test.Monster::op_Explicit(float64)
      IL_002d:  stloc.0
      IL_002e:  ldloc.0
      IL_002f:  call       float64 Test.Monster::op_Implicit(class Test.Monster)
      IL_0034:  conv.r8
      IL_0035:  call       void [mscorlib]System.Console::WriteLine(float64)
    
    
    • Помечено в качестве ответа Druny 20 января 2010 г. 9:50
    • Снята пометка об ответе Druny 20 января 2010 г. 11:12
    • Помечено в качестве ответа I.Vorontsov 21 января 2010 г. 10:06
    • Снята пометка об ответе Druny 21 января 2010 г. 10:17
    • Помечено в качестве ответа I.Vorontsov 22 января 2010 г. 12:01
    20 января 2010 г. 8:44
  • Например, помощью утилиты IldAsm.exe, которая входит в  состав Microsoft SDK. Если установлена VS, то можно через главное меню найти её в подменю Microsft Windows SDK Tools, либо напрямую в папке где установлена Windows SDK, например  С:\Program Files\Microsoft SDKs\Windows\v7.0A\bin\NETFX 4.0 Tools
    • Помечено в качестве ответа Druny 20 января 2010 г. 9:50
    • Снята пометка об ответе Druny 20 января 2010 г. 11:23
    • Помечено в качестве ответа I.Vorontsov 21 января 2010 г. 10:05
    • Снята пометка об ответе Druny 21 января 2010 г. 10:17
    • Помечено в качестве ответа I.Vorontsov 22 января 2010 г. 12:01
    20 января 2010 г. 9:46

Все ответы

  • double c = Demo; - неявно преобразуется тип Monster к double и получается c=3;
    Demo = (Monster)12; - явно преобразовываем тип double к Monster (Demo к даблу не преобразовывается);
    Console.WriteLine(Demo); - неявное преобразование Monster к double;

    19 января 2010 г. 13:20
  • double c = Demo; - неявно преобразуется тип Monster к double и получается c=3;
    Demo = (Monster)12; - явно преобразовываем тип double к Monster (Demo к даблу не преобразовывается);
    Console.WriteLine(Demo); - неявное преобразование Monster к double;


    Ещё вопрос : когда мы описываем выражение double c = Demo; то при его выполнении начинается поиск
    операции преобразования из типа Monster к типу double,  находим операцию преобразования начинается её выполнение
    и имя экземпляра Demo передаётся в параметр операции преобразования (т.е в Monster x) - ЭТО МЫСЛЬ ПРАВИЛЬНАЯ?

    ЕСЛИ ДА то что происходит дальше опиши если не трудно!!!
    19 января 2010 г. 14:34
  • дальше "c" мы присваиваем значение поля "len" объекта "Demo" (return x.len;)

    19 января 2010 г. 14:52
  • дальше "c" мы присваиваем значение поля "len" объекта "Demo" (return x.len;)


    Вот когда имя экземпляра Demo передалось в параметр(Monster x), что там происходит я никак понять немогу!?
    Тип Monster преобразуется в тип double и имя экземпляра класса Demo будет возвращать значение поля len, затем
    это значение присваивается к переменной "c" -ЭТО ТАК?-ну как то все равно туманно !!!!

    Если есть четкое объяснение этому что там происходит при передачи имени экземпляра Demo в параметр Monster x(Вообще какой смысл
    при передачи Demo в параметр Monster x?)
    Отпиши если не трудно!!!

    20 января 2010 г. 4:43
  • Любая операция преобразования - это просто синтаксическое выражение. На самом деле под приведением типов скрывается вызов методов. Когда вы определяете пользовательский оператор приведения, то в действительности вы определяете метод, в котором как параметр передается экземпляр одного типа, а возвращаемым значением является объект преобразованного типа. Реализуя операцию
    double x = Demo; вы на самом деле делаете вызов метода double x = Monster.op_Implicit(Demo);

    Вот как определяются методы приведения в MSIL для вашего случая
    .method public hidebysig specialname static 
            float64  op_Implicit(class Test.Monster x) cil managed
    {
      // Code size       12 (0xc)
      .maxstack  1
      .locals init ([0] float64 CS$1$0000)
      IL_0000:  nop
      IL_0001:  ldarg.0
      IL_0002:  ldfld      float64 Test.Monster::len
      IL_0007:  stloc.0
      IL_0008:  br.s       IL_000a
      IL_000a:  ldloc.0
      IL_000b:  ret
    } // end of method Monster::op_Implicit
    
    .method public hidebysig specialname static 
            class Test.Monster  op_Explicit(float64 v) cil managed
    {
      // Code size       12 (0xc)
      .maxstack  2
      .locals init ([0] class Test.Monster CS$1$0000)
      IL_0000:  nop
      IL_0001:  ldarg.0
      IL_0002:  newobj     instance void Test.Monster::.ctor(float64)
      IL_0007:  stloc.0
      IL_0008:  br.s       IL_000a
      IL_000a:  ldloc.0
      IL_000b:  ret
    } // end of method Monster::op_Explicit
    
    
    
    
    Мы видим, что это обычные статические методы типа
    static double f1(Monster obj)
    static Monster f2(double x),
    правда со специальными именами и прямой вызов их из кода запрещен
    Вот вызовы этих методов в программе при преобразовании типов
    IL_000f:  stloc.0
      IL_0010:  ldloc.0
      IL_0011:  call       float64 Test.Monster::op_Implicit(class Test.Monster)
      IL_0016:  conv.r8
      IL_0017:  stloc.1
      IL_0018:  ldloc.1
      IL_0019:  call       void [mscorlib]System.Console::WriteLine(float64)
      IL_001e:  nop
      IL_001f:  ldc.r8     12.
      IL_0028:  call       class Test.Monster Test.Monster::op_Explicit(float64)
      IL_002d:  stloc.0
      IL_002e:  ldloc.0
      IL_002f:  call       float64 Test.Monster::op_Implicit(class Test.Monster)
      IL_0034:  conv.r8
      IL_0035:  call       void [mscorlib]System.Console::WriteLine(float64)
    
    
    • Помечено в качестве ответа Druny 20 января 2010 г. 9:50
    • Снята пометка об ответе Druny 20 января 2010 г. 11:12
    • Помечено в качестве ответа I.Vorontsov 21 января 2010 г. 10:06
    • Снята пометка об ответе Druny 21 января 2010 г. 10:17
    • Помечено в качестве ответа I.Vorontsov 22 января 2010 г. 12:01
    20 января 2010 г. 8:44
  • Мощно задвинул !!!

    После этого :
    << Реализуя операцию
    double x = Demo; вы на самом деле делаете вызов метода double x = Monster.op_Implicit(Demo);>>
    стало ясно!!!!

    Мне на будущее: Как получить MSIL  из созданного кода?

    20 января 2010 г. 9:32
  • Например, помощью утилиты IldAsm.exe, которая входит в  состав Microsoft SDK. Если установлена VS, то можно через главное меню найти её в подменю Microsft Windows SDK Tools, либо напрямую в папке где установлена Windows SDK, например  С:\Program Files\Microsoft SDKs\Windows\v7.0A\bin\NETFX 4.0 Tools
    • Помечено в качестве ответа Druny 20 января 2010 г. 9:50
    • Снята пометка об ответе Druny 20 января 2010 г. 11:23
    • Помечено в качестве ответа I.Vorontsov 21 января 2010 г. 10:05
    • Снята пометка об ответе Druny 21 января 2010 г. 10:17
    • Помечено в качестве ответа I.Vorontsov 22 января 2010 г. 12:01
    20 января 2010 г. 9:46
  • Ещё коечто не уточнил :

    А вот когда имя экземпляра Demo передается в параметр(Monster x) метода преобразования , то что преобразует свой тип?:
    Имя экземпляра Demo или имя параметра x, и как после этого преобразования мы можем через имя параметра(которое уже наверное имеет тип double ) обращаться к полю len? Что то я опять не допонимаю!!!
    20 января 2010 г. 11:22
  • т.к. Monster-ссылочный тип, то Demo передается в качестве параметра по ссылке. x=Demo - оба одного типа Monster. я не знаю, откуда вы здесь преобразование в дабл увидели. а далее прост возвращается поле len типа double и приравнивается к 'c'
    20 января 2010 г. 12:15
  • Нет у него определено неявное преобразование из Monster в double и явное преобразование из double в Monster
    Когда происходит попытка присваивания
    double c = Demo;
    компилятор видит, что не имеется встроенного преобразования из Monster в double, поэтому начинает искать определенное пользователем преобразование и находит его
    public static implicit operator double (Monster x)
    {
        return x.len;
    }
    в этот метод в качестве параметра передается переменная Demo типа Monster. Этот метод возвращает поле len типа double и это значение присваивается переменной с. Всё, преобразование закончено. Переменная с типа double и ни к каким полям переменной Demo она доступа не имеет, ибо другого типа.
    Уж не знаю как подробней можно разжевать.
    20 января 2010 г. 12:56


  • НО вот когда передается имя экземпяра класса Demo в параметр Monster x, то происходит же преобразование типа
    тип параметра преобразуется в тип указанный в загаловке операции(т.е в double) -НЕПОНЯТЕН СМЫСЛ этого преоброзования ,
    вот передали мы Demo в Monster x -ну, должно же произойти преобразование в double для того чтобы выполнилась
    операция double c=Demo;

    У меня в голове складывается по объяснению, что Demo передалось и всё с ней больше ничего непроисходит, операция возвращает поле len!!!
    Вот когда Demo передалось в параметр x, параметр присвоил её так как типы совпадают, что происходит? что-то должно же
    преобразоваться чтобы выполнилась операция double c=Demo; ?  

    Я извеняюсь конечно что мучаю Вас , но хотелось бы разобраться до конца!!!
    21 января 2010 г. 4:46
  • Если вам самим непонятен смысл преобразования вашего же класса Monster в double, то как другие могут вам его объяснить? Вот какой смысл преобразования класса Колбаса в число?
    Смысл преобразования чего-то во что-то закладывается разработчиком. Вспомните, о чем вы думали в момент написания кода. :)
    21 января 2010 г. 7:44
  • У меня в голове складывается по объяснению, что Demo передалось и всё с ней больше ничего непроисходит, операция возвращает поле len!!!

    Это и есть ваше приведение из Monster в Double. На входе операции имели Demo типа Monster, а ны выход len типа double.
    21 января 2010 г. 8:01
  • Как я понял: Demo передалось в параметр Monster x,  и Demo присваивается к x, затем Demo преобразует
    свой тип Monster в тип double и операция будет возвращать значение переменной len которая присвотся к переменной (с)?Так?



    Мне нужно просто четко понять что там происходит, даже мелочи, так как я свои объснения записываю в тетрадь
    чтоб в последствии если забуду легко можно вспомнить и понять!!!
    21 января 2010 г. 8:36
  • Хм..наверно вам стоит почитать учебник сначала.
    21 января 2010 г. 9:00
  • Тут кое-что дошло до могза,  правильно незнаю!!!

    Объясняю:

    Когда мы передаём переменную Dеmo в параметр Monster x, то она передаётся и происходит преобразование типа т.е переменная Demo заменяется полем len в последствии чего значение поля len присваивается к переменной "double c"

    Если верное, отпишите!!! 

    21 января 2010 г. 9:09
  • Неверно, читайте учебник.
    21 января 2010 г. 12:52
  • Неверно, читайте учебник.


    Если бы в книге это было написано то я бы не описывал этот вопрос здесь!!!

    Об этом там неговорится: Что происходит когда  переменная  Demo присвоилась к параметру Monster x операции преобразования, что сней там происходит, что в последствии операция будет возвращать значение поля len?

    Можете ответить своими словами !!!

    21 января 2010 г. 14:46
  • Вы сами определяете что там с ней происходит, это же пользовательская операция. В вашем случае ничего с ней не происходит, просто возвращается поле len. После этого вы можете спокойно продолжать использовать Demo в коде.

    ЗЫ: Читайте другой  учебник.
    Насколько я понимаю, эту тему надо перенести в какой-нибудь подраздел для начинающих, что ли.
    21 января 2010 г. 15:01
  • Вы сами определяете что там с ней происходит, это же пользовательская операция. В вашем случае ничего с ней не происходит, просто возвращается поле len. После этого вы можете спокойно продолжать использовать Demo в коде.

    ЗЫ: Читайте другой  учебник.
    Насколько я понимаю, эту тему надо перенести в какой-нибудь подраздел для начинающих, что ли.

    Подытожим, что ли :

    Значит при выполнении операции double c = Demo; так как нет неявного преобразования из типа Monster в тип double
    происходит поиск операции преобразования, которая преобразует тип Monster в тип double, компилятор находит 
    такую операцию ,  эта операция выполняется (т.е тип Monster преобразуется в тип double) и после выполнения эта операция
    возвращает значение поля len и это значение присваивается к переменной double  c 

    Т.Е  как бы операция преобразования выдаст нам, чему будет равно преобразование типа Monster к типу double
    при выполнении операции double c =Demo;- т.е операция выдаст нам чему здесь будет  равно неявное преобразование из типа Monster
    к типу double

    Наверное Так?
    21 января 2010 г. 16:02
  • Вы сами определяете что там с ней происходит, это же пользовательская операция. В вашем случае ничего с ней не происходит, просто возвращается поле len. После этого вы можете спокойно продолжать использовать Demo в коде.

    ЗЫ: Читайте другой  учебник.
    Насколько я понимаю, эту тему надо перенести в какой-нибудь подраздел для начинающих, что ли.

    Подытожим, что ли :

    Значит при выполнении операции double c = Demo; так как нет неявного преобразования из типа Monster в тип double
    происходит поиск операции преобразования, которая преобразует тип Monster в тип double, компилятор находит 
    такую операцию ,  эта операция выполняется (т.е тип Monster преобразуется в тип double) и после выполнения эта операция
    возвращает значение поля len и это значение присваивается к переменной double  c 

    Т.Е  как бы операция преобразования выдаст нам, чему будет равно преобразование типа Monster к типу double
    при выполнении операции double c =Demo;- т.е операция выдаст нам чему здесь будет  равно неявное преобразование из типа Monster
    к типу double

    Наверное Так?

    да! поздравляю!
    • Предложено в качестве ответа Alexander V. Vasilyev 22 января 2010 г. 12:38
    22 января 2010 г. 12:38
  • нет! переменная Demo не меняется!
    22 января 2010 г. 12:39