Можно ли использовать ссылку внутри функции С#, например С++?

В С++ я могу это сделать:

 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();