Почему C # не поддерживает возврат ссылок? - PullRequest
139 голосов
/ 14 июня 2011

Я читал, что .NET поддерживает возврат ссылок, а C # - нет.Есть ли особая причина?Почему я не могу сделать что-то вроде:

static ref int Max(ref int x, ref int y) 
{ 
  if (x > y) 
    return ref x; 
  else 
    return ref y; 
} 

Ответы [ 4 ]

187 голосов
/ 14 июня 2011

Этот вопрос был темой моего блога 23 июня 2011 года . Спасибо за отличный вопрос!

Команда C # рассматривает это для C # 7. Подробнее см. https://github.com/dotnet/roslyn/issues/5233.

ОБНОВЛЕНИЕ: функция добралась до C # 7!


Вы правы; .NET поддерживает методы, которые возвращают управляемые ссылки на переменные. .NET также поддерживает локальные переменные , которые содержат управляемые ссылки на другие переменные. (Однако обратите внимание, что .NET не поддерживает поля или массивы , которые содержат управляемые ссылки на другие переменные, поскольку это слишком усложняет историю сбора мусора. не преобразуется в объект и поэтому не может использоваться в качестве аргументов типа для универсальных типов или методов.)

Комментатор "RPM1984" по какой-то причине попросил процитировать этот факт. RPM1984 Я рекомендую вам прочитать Раздел 8.2.1.1 «Управляемые указатели и связанные типы» спецификации CLI для получения информации об этой функции .NET.

Вполне возможно создать версию C #, которая поддерживает обе эти функции. Затем вы могли бы делать такие вещи, как

static ref int Max(ref int x, ref int y) 
{ 
  if (x > y) 
    return ref x; 
  else 
    return ref y; 
} 

, а затем позвоните по номеру

int a = 123;
int b = 456; 
ref int c = ref Max(ref a, ref b); 
c += 100;
Console.WriteLine(b); // 556!

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

Мы рассмотрели эту функцию и фактически реализовали ее достаточно, чтобы показать другим внутренним командам, чтобы получить их отзывы. Однако в настоящее время, основываясь на нашем исследовании , мы считаем, что эта функция не имеет достаточно широкой привлекательности или убедительных вариантов использования, чтобы превратить ее в реальную поддерживаемую языковую функцию . У нас есть другие более высокие приоритеты и ограниченное количество времени и усилий, поэтому мы не собираемся делать эту функцию в ближайшее время.

Кроме того, для правильной работы потребуются некоторые изменения в CLR. В настоящее время CLR рассматривает методы возврата-возврата как допустимые , но не проверяемые , потому что у нас нет детектора, который обнаруживает эту ситуацию:

ref int M1(ref int x)
{
    return ref x;
}

ref int M2()
{
    int y = 123;
    return ref M1(ref y); // Trouble!
}

int M3()
{
    ref int z = ref M2();
    return z;
}

M3 возвращает содержимое локальной переменной M2, но время жизни этой переменной закончилось! Можно написать детектор, который определяет использование реф-возвратов, которые явно не нарушают безопасность стека. Что бы мы сделали, это напишем такой детектор, и если бы детектор не смог доказать безопасность стека, то мы бы не допустили использование ref-возвратов в этой части программы. Для этого не так много работы разработчиков, но для команд тестирования очень тяжело убедиться, что у нас действительно есть все случаи. Это просто еще одна вещь, которая увеличивает стоимость функции до такой степени, что прямо сейчас выгоды не перевешивают затраты.

Если вы можете описать мне, почему вы хотите эту функцию, я был бы очень признателен за это . Чем больше у нас информации от реальных клиентов о том, почему они этого хотят, тем больше вероятность, что она когда-нибудь попадет в продукт. Это милая маленькая функция, и я бы хотел как-то донести ее до покупателей, если будет достаточно интереса.

(См. Также связанные вопросы Можно ли вернуть ссылку на переменную в C #? и Можно ли использовать ссылку внутри функции C #, например, C ++? )

22 голосов
/ 14 июня 2011

Вы говорите о методах, которые возвращают ссылку на тип значения. Единственный встроенный пример в C #, о котором я знаю, - это средство доступа к массиву типа значения:

public struct Point
{
    public int X { get; set; }
    public int Y { get; set; }
}

и теперь создайте массив этой структуры:

var points = new Point[10];
points[0].X = 1;
points[0].Y = 2;

В этом случае points[0], массив indexer , возвращает ссылку на struct. Невозможно написать собственный собственный индексатор (например, для пользовательской коллекции), который имеет такое же поведение "возврата ссылки".

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

1 голос
/ 16 апреля 2017

C # 7.0 поддерживает возврат ссылок. Смотрите мой ответ здесь .

1 голос
/ 01 сентября 2016

Вы всегда можете сделать что-то вроде:

public delegate void MyByRefConsumer<T>(ref T val);

public void DoSomethingWithValueType(MyByRefConsumer<int> c)
{
        int x = 2;
        c(ref x);
        //Handle potentially changed x...
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...