Могу ли я использовать ссылку внутри функции C #, например, C ++? - PullRequest
6 голосов
/ 20 июля 2010

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

 int flag=0,int1=0,int2=1;
 int &iRef = (flag==0?int1:int2);
 iRef +=1;

с эффектом увеличения int1.

Мне нужно изменить какой-то старый код на C #, и было бы очень полезно, если бы я мог сделать что-то подобное, но я думаю ... может и нет Кто-нибудь? * * 1006

Ответы [ 7 ]

8 голосов
/ 20 июля 2010

ОБНОВЛЕНИЕ: функция, обсуждаемая ниже, была наконец добавлена ​​в C # 7.


Функция, которую вы хотите - сделать псевдонимами управляемых локальных переменных , не поддерживается в C #. Вы можете сделать это с формальными параметрами - вы можете сделать формальный параметр, который является псевдонимом любой переменной, - но вы не можете сделать local , который является псевдонимом любой переменной. *

Тем не менее, техническая сложность не мешает нам сделать это; система типов CLR поддерживает «ref локальные переменные». (Он также поддерживает типы возврата ref, но не поддерживает поля ref.)

Несколько лет назад я фактически написал прототип версии C #, которая поддерживала локальные ссылки и возвращаемые типы ссылок, и это работало очень хорошо, поэтому у нас есть эмпирические доказательства того, что мы можем сделать это успешно. Однако маловероятно, что эта функция будет добавлена ​​в C # в ближайшее время, если вообще когда-либо. Подробнее см. http://ericlippert.com/2011/06/23/ref-returns-and-ref-locals/.

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

См. Также связанный вопрос: Почему C # не поддерживает возврат ссылок?

5 голосов
/ 20 июля 2010

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

Если вы все еще хотите это сделать, см. Класс 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 голосов
/ 16 апреля 2017

Да, вы можете сделать это с C # 7.0 . Он поддерживает возврат ссылок и хранение ссылок. Смотрите мой ответ здесь .

2 голосов
/ 20 июля 2010

Если все, что вам нужно, это изменить тип значения внутри функции, то передайте параметр с ключевым словом ref.

int i = 0;</p> <pre><code>void increment(ref int integer) { integer++; } increment(ref i);

1 голос
/ 20 июля 2010

Вы можете использовать Делегат действия , например:

int flag = 0, int1 = 0, int2 = 0;
Action increment = flag == 0 ? (Action) (() => ++int1) : () => ++int2;
increment();
1 голос
/ 20 июля 2010

В 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 копирует ссылку, и вышеописанное работает ...

1 голос
/ 20 июля 2010

Фрайд нет.Вы можете сделать это с помощью небезопасного кода и указателей, например:

    int flag=0,int1=0,int2=1;
    unsafe
    {
        int *iRef = (flag==0? &int1:&int2);
        *iRef +=1;
    }

(не говоря уже о том, что это хорошая идея или что-то в этом роде:))

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...