Вызов метода в структуре? - PullRequest
26 голосов
/ 05 мая 2011

Когда мы вызываем метод для объекта, тогда ссылка на объект передается неявно методу.

Итак, мой вопрос: что происходит, когда метод вызывается в структуре?Это похоже на занятия в этом аспекте?

Ответы [ 3 ]

25 голосов
/ 05 мая 2011

Согласно спецификации CIL указатель this передается по ссылке / как управляемый указатель. Как предположил Binary Worrier, это особенность CIL.

Экземпляр и виртуальные методы классы должны быть закодированы, чтобы ожидать ссылка на экземпляр класса как этот указатель. В отличие от этого, экземпляр и виртуальные методы стоимости типы должны быть закодированы, чтобы ожидать управляемый указатель (см. раздел I) на распакованный экземпляр типа значения. CLI должен преобразовать коробочное значение введите в управляемый указатель на распакованный тип значения в штучной упаковке тип передается как указатель this виртуальный метод, реализация которого предоставляется распакованным типом значения.

Таким образом, с точки зрения высокого уровня вызов метода экземпляра ссылочного типа (класса) выглядит следующим образом:

MyClass myClass = MyClass_Constructor();

MyClass_MyInstanceMethod(myClass, myFirstParameter);
//                       ^
//                       The "this" argument

И вызов метода экземпляра типа значения (структуры), подобного этому:

MyStruct myStruct = MyStruct_Constructor();

MyStruct_MyInstanceMethod(ref myStruct, myFirstParameter);
//                        ^
//                        The "this" argument
21 голосов
/ 05 мая 2011

Флориан прав;Еще несколько подробностей, пока мы находимся по теме:

Когда мы вызываем метод для объекта, тогда ссылка на объект передается неявно методу.

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

class C
{
    int y;
    public void M(int x) 
    { 
        Console.WriteLine(x + y); 
    }
}
...
C c = new C();
c.M(10);

фактически совпадает с

class C
{
    int y;
    public static void M(C _this, int x) 
    { 
        Console.WriteLine(x + _this.y); 
    }
}
...
C c = new C();
C.M(c, 10);

То есть каждый экземпляр метода имеет скрытый параметр "this",и метод «действительно» статический.

Итак, мой вопрос: что происходит, когда метод вызывается в структуре?Это похоже на классы в этом аспекте?

Да.Вместо ссылки на экземпляр передается псевдоним переменной, содержащей структуру.Вот как методы struct могут изменять структуру.(Конечно, изменение структуры - плохая практика, но иногда необходимо.)

struct S
{
    int y;
    public void M(int x) 
    { 
        Console.WriteLine(x + y); 
    }
}
...
S s = new S();
s.M(10);

логически совпадает с

struct S
{
    int y;
    public static void M(ref S _this, int x) 
    { 
        Console.WriteLine(x + _this.y); 
    }
}
...
S s = new S();
S.M(ref s, 10);

. Тогда возникает интересный вопрос: что, еслиполучатель "не является переменной?(*) Вы можете использовать только ссылку на переменную.Предположим, у вас есть:

GetAnS().M(10); 

???Что будет потом?

Мы создадим переменную для вас.Это становится

S temporary = GetAnS();
temporary.M(10);

, и теперь получатель является переменной, поэтому мы можем сделать «скрытый этот параметр» псевдонимом для него.

(*) Здесь есть и другие интересные случаи:ну, например, что если структура изменяемая, но переменная доступна только для чтения и т. д.

2 голосов
/ 05 мая 2011

Некоторое время назад я написал серию постов на эту тему. В частности, http://www.simple -talk.com / сообщество / блоги / simonc / archive / 2010/11/02 / 95489.aspx

В IL вы можете хранить управляемый указатель в стеке, который похож на ссылку на объект, за исключением того, что он может указывать на вещи, отличные от ссылок на объект. Существуют специальные инструкции для получения управляемого указателя на что-либо, например ldloca, который получает указатель на локальную переменную, или ldelema, который получает указатель на определенный элемент в массиве.

Это безопасные указатели, поскольку сборщик мусора знает о них и поэтому изменяет их, если объект, на который вы указываете, перемещается ГХ.

Для вызова методов в структурах требуется управляемый указатель на структуру (которая может находиться в любом месте памяти - в стеке, в списке аргументов, в другом объекте в куче), для которого должен выполняться метод как this указатель. Для вызова методов ссылочных типов требуется ссылка на объект.

Это вызывает некоторые проблемы при вызове методов для универсальных типов, которые могут быть значениями или ссылочными типами. Я взгляну на это в следующих постах в блоге.

Одним из побочных эффектов возможности использования управляемых указателей для типов значений является то, что в IL можно вызывать метод для типа в штучной упаковке , не распаковывая его:

// you have a struct on the stack
box MyStructType    // this copies the value on the stack to an object on the heap
unbox MyStructType  // this returns a managed pointer to the value type instance in its boxed form. It doesn't copy the value itself back to the stack (despite the name)
call instance void MyStructType::MyMethod()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...