Подтвердить что ты не робот

Вызов метода в структуре?

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

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

4b9b3361

Ответ 1

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

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

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

MyClass myClass = MyClass_Constructor();

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

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

MyStruct myStruct = MyStruct_Constructor();

MyStruct_MyInstanceMethod(ref myStruct, myFirstParameter);
//                        ^
//                        The "this" argument

Ответ 2

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

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

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

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);

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

GetAnS().M(10); 

??? Что происходит потом?

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

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

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

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

Ответ 3

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

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

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

Вызов метода для структур требует управляемого указателя на структуру (которая может быть где угодно в памяти - в стеке, в списке аргументов, в другом объекте в куче), метод должен выполняться как 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()