Можно ли использовать ссылку внутри функции С#, например С++?
В С++ я могу это сделать:
int flag=0,int1=0,int2=1;
int &iRef = (flag==0?int1:int2);
iRef +=1;
с тем, что int1 увеличивается.
Мне нужно изменить старый код С#, и было бы очень полезно, если бы я мог сделать что-то подобное, но я думаю... может быть, нет. Кто-нибудь?
Ответы
Ответ 1
Вы можете сделать это - или, по крайней мере, что-то очень похожее на то, что вы хотите - но, вероятно, лучше всего найти другой подход. Например, вы можете обернуть целые числа в простой ссылочный тип.
Если вы все еще хотите это сделать, см. класс Ref<T>
, опубликованный Эриком Липпертом здесь:
sealed class Ref<T>
{
private readonly Func<T> getter;
private readonly Action<T> setter;
public Ref(Func<T> getter, Action<T> setter)
{
this.getter = getter;
this.setter = setter;
}
public T Value { get { return getter(); } set { setter(value); } }
}
public class Program
{
public static void Main()
{
int flag=0,int1=0,int2=1;
Ref<int> iRef = (flag == 0 ?
new Ref<int>(() => int1, z => { int1 = z; }) :
new Ref<int>(() => int2, z => { int2 = z; }));
iRef.Value += 1;
Console.WriteLine(int1);
}
}
Вывод:
1
Ответ 2
UPDATE: функция, рассмотренная ниже, была наконец добавлена в С# 7.
Функция, которую вы хотите - сделать управляемые локальные псевдонимы переменных, не поддерживается в С#. Вы можете сделать это с помощью формальных параметров - вы можете сделать формальный параметр, который является псевдонимом любой переменной, но вы не можете создать локальный, который является псевдонимом любой переменной.
Однако технические трудности не мешают нам сделать это; система CLR поддерживает "ref local local". (Он также поддерживает типы возврата ref, но не поддерживает поля ref.)
Несколько лет назад я на самом деле написал прототип версии С#, которая поддерживала ref locals и возвращала возвращаемые типы, и она работала очень хорошо, поэтому у нас есть эмпирические доказательства того, что мы можем сделать это успешно. Однако очень маловероятно, что эта функция будет добавлена в С# в любое время, если вообще когда-либо. Подробнее см. http://ericlippert.com/2011/06/23/ref-returns-and-ref-locals/.
Я отмечаю, что если бы я был вами, я бы избегал этого на любом языке. Написание программ, в которых две переменные совместно используют одно и то же хранилище, делает код, который трудно читать, трудно понять, трудно модифицировать и трудно поддерживать.
См. также соответствующий вопрос: Почему С# не поддерживает возврат ссылок?
Ответ 3
Если вам нужно только изменить тип значения внутри функции, передайте параметр с помощью ключевого слова ref
.
int i = 0;
void increment(ref int integer)
{
integer++;
}
increment(ref i);
код >
Ответ 4
Да, вы можете сделать это с помощью С# 7.0. Он поддерживает возврат ссылок и сохранение ссылок. См. Мой ответ здесь.
Ответ 5
Не боится. Вы можете сделать это с помощью небезопасного кода и указателей следующим образом:
int flag=0,int1=0,int2=1;
unsafe
{
int *iRef = (flag==0? &int1:&int2);
*iRef +=1;
}
(не говоря о том, что хорошая идея или что-то еще:))
Ответ 6
В С# нет прямой эквивалентности. Есть несколько вариантов -
Вы можете использовать небезопасный код и указатели, как предложено dkackman.
Другой альтернативой является использование ссылочного типа (класса), который содержит значение. Для exmaple:
// Using something like
public class Wrapped<T> {
public Wrapped(T initial) {
this.Value = initial;
}
public T Value { get; set; }
}
// You can do:
bool flag=false;
var int1 = new Wrapped<int>(0);
var int2 = new Wrapped<int>(1);
Wrapped<int> iRef = flag ? int2 : int1;
iRef.Value = iRef.Value + 1;
Поскольку вы работаете со ссылками на класс, назначение iRef
копирует ссылку, и выше работает...
Ответ 7
Вы можете использовать делегат действий следующим образом:
int flag = 0, int1 = 0, int2 = 0;
Action increment = flag == 0 ? (Action) (() => ++int1) : () => ++int2;
increment();