Как сохранить ссылку на целое число в C #?

Возможный дубликат:
Как назначить по ссылке поле класса в C #?

Всем привет - подскажите как заставить это работать? В принципе, мне нужен целочисленный ссылочный тип (int * будет работать на C ++)

class Bar
{
   private ref int m_ref;     // This doesn't exist

   public A(ref int val)
   {
      m_ref = val;
   }

   public void AddOne()
   {
      m_ref++;
   }
}

class Program
{
   static void main()
   {
      int foo = 7;
      Bar b = new Bar(ref foo);
      b.AddOne();
      Console.WriteLine(foo);    // This should print '8'
   }
 }

Обязательно ли боксировать?

Изменить: Возможно, мне следовало быть более конкретным. Я пишу класс BitAccessor, который просто разрешает доступ к отдельным битам. Вот мое желаемое использование:

class MyGlorifiedInt
{
   private int m_val;
   ...
   public BitAccessor Bits {
      return new BitAccessor(m_val);
   }
}

Использование:

MyGlorifiedInt val = new MyGlorifiedInt(7);
val.Bits[0] = false;     // Bits gets a new BitAccessor
Console.WriteLine(val);  // outputs 6

Чтобы BitAccessor мог изменять m_val, ему нужна ссылка на него. Но я хочу использовать этот BitAccessor во многих местах, просто ссылаясь на желаемое целое число.


person Jonathon Reinhart    schedule 06.06.2010    source источник
comment
Какая у вас здесь цель? Это в основном противоречит идее управляемого кода; если бы вы могли сохранить ссылку на foo в каком-либо другом классе, время жизни которого не связано с main, что произойдет, когда main завершится и фрейм стека, в котором находится foo жизней, будет уничтожен?   -  person tzaman    schedule 06.06.2010
comment
@tzaman, моя правка прояснила мои намерения? @abatishchev - Я бы хотел, но ни один из ответов не соответствует тому, что я искал. Может, это невозможно.   -  person Jonathon Reinhart    schedule 07.06.2010
comment
Почему бы небезопасным указателям не делать то, что вы ищете? Вы даже упомянули, что указатели помогли бы, если бы это было на C ++.   -  person David Brown    schedule 07.06.2010
comment
Это дубликат stackoverflow.com/questions/2980463/ См. мой ответ там, чтобы объяснить, почему нельзя сохранить ссылку на переменную в поле, и способы обойти это ограничение.   -  person Eric Lippert    schedule 07.06.2010
comment
да, я думаю, я понимаю, что вы сейчас пытаетесь сделать. Я ответил, как это сделать.   -  person tzaman    schedule 07.06.2010


Ответы (4)


Вы не можете сохранить ссылку на такое целое число напрямую, но вы можете сохранить ссылку на объект GlorifiedInt, содержащий его. В вашем случае я бы, вероятно, сделал так, чтобы класс BitAccessor был вложен внутрь GlorifiedInt (чтобы он получил доступ к закрытым полям), а затем передал ему ссылку на this при его создании, которую он затем может использовать для доступа к m_val поле. Вот пример того, что вам нужно:

class Program
{
    static void Main(string[] args)
    {
        var g = new GlorifiedInt(7);
        g.Bits[0] = false;
        Console.WriteLine(g.Value); // prints "6"
    }
}

class GlorifiedInt
{
    private int m_val;

    public GlorifiedInt(int value)
    {
        m_val = value;
    }

    public int Value
    {
        get { return m_val; }
    }

    public BitAccessor Bits
    {
        get { return new BitAccessor(this); }
    }

    public class BitAccessor
    {
        private GlorifiedInt gi;

        public BitAccessor(GlorifiedInt glorified)
        {
            gi = glorified;
        }

        public bool this[int index]
        {
            get 
            {
                if (index < 0 || index > 31)
                    throw new IndexOutOfRangeException("BitAcessor");
                return (1 & (gi.m_val >> index)) == 1; 
            }
            set 
            {
                if (index < 0 || index > 31)
                    throw new IndexOutOfRangeException("BitAcessor");
                if (value)
                    gi.m_val |= 1 << index;
                else
                    gi.m_val &= ~(1 << index);
            }
    }
    }
}
person tzaman    schedule 07.06.2010
comment
Спасибо! Это то, что я искал. И ваш BitAccessor выглядит идентично тому, что я написал. Единственное, что было бы лучше, - это иметь возможность применить это к любому целому числу, но это невозможно сделать без ссылки. Однако ваше решение отлично подходит для моего проекта. - person Jonathon Reinhart; 18.06.2010
comment
Вы также можете добавить это: общедоступный статический неявный оператор GlorifiedInt (int v) {return new GlorifiedInt (v); } Это позволяет писать, например, GlorifiedInt a = 10; - person Aidan; 15.02.2018

Вам не нужно иметь ссылку на целое число - просто поместите целое число в ссылочный тип - это почти то, что вы уже сделали. Просто измените эту строку:

Console.WriteLine(foo);

to:

Console.WriteLine(bar.Value);

Затем добавьте соответствующий метод доступа к классу Bar и удалите ошибки компиляции (удалите ключевые слова ref).

Альтернативный подход - передать целое число в функцию по ссылке:

static void AddOne(ref int i)
{
    i++;
}

static void Main()
{
    int foo = 7;
    AddOne(ref foo);
    Console.WriteLine(foo);
}

Вывод:

8
person Mark Byers    schedule 06.06.2010
comment
Ни то, ни другое не является именно тем, о чем просит OP, который, похоже (если я правильно понимаю), является каким-то способом сохранить ссылку на локальный int foo в Main внутри объекта Bar, так что вызовы других методов в экземпляре Bar изменяют значение foo в Main. Не уверен, что это действительно возможно на C #, не вдаваясь в небезопасный код ... - person tzaman; 06.06.2010
comment
@tzaman, первый - это то, о чем просит OP, с точки зрения поведения; помните, мы заменили Main использование foo на bar.Value. Однако на самом деле это просто ручной бокс, которого ОП считает, что он не хочет. - person ; 07.06.2010

Вы не указали, что были против небезопасного кода, поэтому это должно сработать:

unsafe class Bar {
    private int* m_ref;

    public Bar(int* val) {
        m_ref = val;
    }

    public void AddOne() {
        *m_ref += 1;
    }
}

unsafe class Program {
    static void Main() {
        int foo = 7;
        Bar b = new Bar(&foo);
        b.AddOne();
        Console.WriteLine(foo);    // prints 8
        Console.ReadLine();
    }
}

Я никогда не использовал указатели в C #, но похоже, что это работает. Я просто не уверен, каковы возможные побочные эффекты.

person David Brown    schedule 06.06.2010
comment
Вам категорически запрещено это делать. Вы не должны никогда хранить ссылку на указатель стека подобным образом. Если указатель выживает после удаления кадра стека, происходят плохие вещи. Вот почему этот шаблон вообще недопустим в безопасном коде! Небезопасный код требует, чтобы вы знали, каковы ВСЕ возможные побочные эффекты; вот почему это небезопасно. - person Eric Lippert; 07.06.2010
comment
Я каждый день узнаю что-то новое. Спасибо за объяснение. :) - person David Brown; 07.06.2010

Это не дает прямого ответа на ваш вопрос, но можете ли вы просто использовать System.Collections.BitArray?

Просто интересно, не изобретаете ли вы колесо заново?

person Chris Dunaway    schedule 07.06.2010
comment
покажите, пожалуйста, как использовать BitArray в этом сценарии - person gdbdable; 04.08.2017