Я читал, что .NET поддерживает возврат ссылок, а C # - нет. Есть особая причина? Почему я не могу сделать что-то вроде:
static ref int Max(ref int x, ref int y)
{
if (x > y)
return ref x;
else
return ref y;
}
c#
.net
reference
return-type
Том Сардуй
источник
источник
return ref x
C# 7
:)Ответы:
Этот вопрос был темой моего блога 23 июня 2011 года . Спасибо за отличный вопрос!
Команда C # рассматривает это для C # 7. Подробнее см. Https://github.com/dotnet/roslyn/issues/5233 .
ОБНОВЛЕНИЕ: эта функция вошла в C # 7!
Ты прав; .NET поддерживает методы, возвращающие управляемые ссылки на переменные. .NET также поддерживает локальные переменные, которые содержат управляемые ссылки на другие переменные. (Обратите внимание, однако, что .NET не поддерживает поля или массивы, которые содержат управляемые ссылки на другие переменные, потому что это чрезмерно усложняет сборку мусора. Кроме того, типы «управляемая ссылка на переменную» не могут быть преобразованы в объект и поэтому не могут использоваться в качестве аргументы типа для универсальных типов или методов.)
Комментатор "RPM1984" почему-то попросил ссылку на этот факт. RPM1984 Я рекомендую вам прочитать спецификацию интерфейса командной строки, раздел 8.2.1.1, «Управляемые указатели и связанные типы», для получения информации об этой функции .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 ++? )
источник
y
живых после возвращения изM2
? Я ожидал, что эта функция будет работать как лямбды, захватывающие локальных жителей. Или поведение, которое вы предложили, связано с тем, как CLR обрабатывает этот сценарий?Вы говорите о методах, возвращающих ссылку на тип значения. Единственный известный мне встроенный пример 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]
массива возвращает ссылку на структуру. Невозможно написать собственный индексатор (например, для настраиваемой коллекции), который имеет такое же поведение «возврат ссылки».Я не разрабатывал язык C #, поэтому я не знаю всех причин, по которым он не поддерживается, но я думаю, что краткий ответ может быть таким: мы прекрасно справимся и без него.
источник
Вы всегда можете сделать что-нибудь вроде:
public delegate void MyByRefConsumer<T>(ref T val); public void DoSomethingWithValueType(MyByRefConsumer<int> c) { int x = 2; c(ref x); //Handle potentially changed x... }
источник
C # 7.0 поддерживает возврат ссылок. Смотрите мой ответ здесь .
источник