В C++ я могу сделать это:
int flag=0,int1=0,int2=1;
int &iRef = (flag==0?int1:int2);
iRef +=1;
с эффектом, что int1 увеличен.
Я должен изменить некоторый более старый код c#, и было бы действительно полезно, если я мог бы сделать что-то подобное, но я думаю..., возможно, нет. Кто-либо?
Вы можете сделать это - или, по крайней мере, что-то очень похожее на то, что вы хотите, но вероятно, лучше найти другой подход. Например, вы можете заключить целые числа в простой ссылочный тип.
Если вы все еще хотите это сделать, см. Класс Ref
, опубликованный Эриком Липпертом здесь :
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
Если все, что вам нужно, это изменить тип значения в функции, то передайте параметр с ключевым словом ref
.
int i = 0;
void increment(ref int integer)
{
integer++;
}
increment(ref i);
Не пугайтесь. Вы могли бы сделать это с помощью небезопасного кода и таких указателей:
int flag=0,int1=0,int2=1;
unsafe
{
int *iRef = (flag==0? &int1:&int2);
*iRef +=1;
}
(не говоря уже о том, что это хорошая идея или что-то в этом роде :))
В C # нет прямого эквивалента. Есть несколько вариантов -
Вы можете использовать небезопасный код и указатели, как предлагает dkackman .
Другой альтернативой является использование ссылочного типа (класса), который содержит значение. Например:
// 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
копирует ссылку, и вышеуказанное работает ...
Вы можете использовать делегат действия следующим образом:
int flag = 0, int1 = 0, int2 = 0;
Action increment = flag == 0 ? (Action) (() => ++int1) : () => ++int2;
increment();
ОБНОВЛЕНИЕ: Обсуждаемая ниже функция была наконец добавлена в C # 7.
Функция, которую вы хотите - сделать управляемым псевдонимы локальных переменных не поддерживаются в C #. Вы можете сделать это с помощью формальных параметров - вы можете сделать формальный параметр, который является псевдонимом любой переменной - но вы не можете сделать локальным , который является псевдонимом любой переменной.
Однако нет технических трудностей, которые мешают нам сделать это; система типов CLR поддерживает "локальные переменные ref".(Он также поддерживает возвращаемые типы ref, но не поддерживает поля ref.)
Несколько лет назад я фактически написал прототипную версию C #, которая поддерживала локальные переменные ref и возвращаемые типы ref, и она работала очень хорошо, так что у нас есть эмпирические доказательства что мы можем сделать это успешно. Однако маловероятно, что эта функция будет добавлена в C # в ближайшее время, если вообще когда-либо. Подробнее см. http://ericlippert.com/2011/06/23/ref-returns-and-ref-locals/ .
Замечу, что на вашем месте я бы избегал этого на любом языке. Написание программ, в которых две переменные используют одно и то же хранилище, делает код трудным для чтения, понимания, изменения и сопровождения.
См. Также связанный с этим вопрос: Почему C # не поддерживает возврат ссылок?