В C # есть способ имитировать передачу указателя (без использования ключевого слова unsafe) - PullRequest
0 голосов
/ 25 января 2012

Без использования ключевого слова «Небезопасно» можно выполнить следующее:

Передача поля в качестве параметра функции.Функция может периодически изменять значение этого поля.

, поэтому, если у меня есть:

int MyField;

и:

MyFunction(ref MyField)

функция может хранить указатель на MyField и меняем его значение по мере необходимости.

В C ++ мы просто передаем указатель на значение, а затем меняем его по мере необходимости, но я пытаюсь выяснить, можно ли это сделать в C #,Я предполагаю, что это можно сделать с помощью размышлений.

Ответы [ 5 ]

10 голосов
/ 25 января 2012

Позвольте мне перефразировать этот вопрос:

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

Нет.

В системе типов CLR ссылки на переменные могут быть переданы как формальные параметры . Они также могут быть возвращены из вызовов методов и , хранящихся в локальных переменных, которые, как известно, имеют короткое время жизни . (C # не поддерживает последние две функции; подробности см. В моей статье на эту тему: http://blogs.msdn.com/b/ericlippert/archive/2011/06/23/ref-returns-and-ref-locals.aspx.)

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

Причина этого ограничения в том, что вы не можете иметь все четыре из этих желательных качеств одновременно :

  • Любая переменная может быть передана по ссылке
  • Всегда безопасно получить доступ к ссылке на переменную (в безопасном коде; если переменная является разыменованием указателя из небезопасного кода, тогда вы несете ответственность за обеспечение ее безопасности, а не за время выполнения.)
  • Переменные с коротким сроком службы можно очистить без сбора мусора (т. Е. Путем «извлечения стека» или повторного использования регистров или любой другой системы восстановления памяти, не основанной на gc, используемой для пула краткосрочного хранения. )
  • Переменные ссылки могут храниться в местах долгосрочного хранения

Один из них должен дать, и дизайнеры CLR выбрали последний, который проиграл. Дизайнеры C и C ++ выбрали в качестве второго проигравшего.

Полагаю, это можно сделать с помощью отражения.

Не может. Но это можно сделать с делегатами.

class C
{
    private Action<int> setter;
    public void RecordSetter(Action<int> setter)
    {
        this.setter = setter;
    }
    public void SetIt(int x)
    {
        this.setter(x);
    }
}

и теперь вы можете сказать:

class D
{
    int myField;
    void M()
    {
        C c = new C();
        c.RecordSetter(x=>{myField = x; });
        c.SetIt(123);
        Console.WriteLine(myField);
    }
}

Сборщик мусора обеспечит, чтобы экземпляр D оставался в живых до тех пор, пока экземпляр C остается живым.

6 голосов
/ 25 января 2012

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

2 голосов
/ 25 января 2012

Использование ключевого слова ref разработано в явном виде, чтобы код не выполнял то, о чем я думаю, что вы запрашиваете (т. Е. Возможность иметь функцию, вызывающую изменение места хранения, передаваемого через параметр 'ref' после его выхода),Если вы хотите, чтобы код беспорядочно сохранялся и передавал изменяемые ссылки на что-либо, сделайте его открытым полем в объекте-оболочке или создайте экземпляр одноэлементного массива и передайте его.

0 голосов
/ 25 января 2012

Нет .... вы не можете сохранить ссылку ....

Но вы можете заключить ее в класс и сохранить ссылку на нее.

0 голосов
/ 25 января 2012

Используя параметр Ref , вы передаете ссылку на MyField

...