How to store a reference to an integer in C#? [duplicate]
Asked Answered
C

4

12

Possible Duplicate:
How do I assign by “reference” to a class field in c#?

Hello everyone - tell me how to make this work? Basically, I need an integer reference type (int* would work in 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'
   }
 }

Do I have to use boxing?

Edit: Perhaps I should have been more specific. I'm writing a BitAccessor class, that simply allows access to individual bits. Here's my desired usage:

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

Usage:

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

For BitAccessor to be able to modify m_val, it needs a reference to it. But I want to use this BitAccessor many places, with just a reference to the desired integer.

Cocotte answered 6/6, 2010 at 19:44 Comment(5)
What's your objective here? This is basically going against the whole idea of managed code; if you could store a ref to foo in some other class whose lifetime isn't linked to main, what happens when main exits and the stack frame where foo lives is destroyed?Mithgarthr
@tzaman, did my edit clear up my intentions? @abatishchev - I would like to, but neither of the answers do quite what I was looking for. Maybe it's not possible.Cocotte
Why wouldn't unsafe pointers do what you're looking for? You even mentioned pointers would do the trick if this were in C++.Ori
This is a duplicate of #2980963 See my answer there for an explanation of why you cannot store a ref to a variable in a field, and ways of getting around that restriction.Nyeman
yeah, I think I see what you're trying to do now. I've answered with a way to do just that.Mithgarthr
M
7

You can't store a reference to an integer like that directly, but you can store a reference to the GlorifiedInt object containing it. In your case, what I'd probably do is make the BitAccessor class nested inside GlorifiedInt (so that it gets access to private fields), and then pass it a reference to this when it's created, which it can then use to access the m_val field. Here's an example which does what you're looking for:

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);
            }
    }
    }
}
Mithgarthr answered 7/6, 2010 at 5:36 Comment(2)
Thank you! This is what I was looking for. And your BitAccessor looks identical to the one I'd written. The only thing better that'd be nice, would be to be able to apply this to any Integer - but that can't be done without the reference. Your solution works fine for the scope of my project, however.Cocotte
You can add this also: public static implicit operator GlorifiedInt(int v) { return new GlorifiedInt(v); } This allows you to write e.g. GlorifiedInt a = 10;Agnesagnese
F
4

You don't need to have a reference to an integer - just put your integer inside a reference type - which is almost what you've done already. Just change this line:

Console.WriteLine(foo);

to:

Console.WriteLine(bar.Value);

Then add an appropriate accessor to the class Bar, and remove the compile errors (remove the ref keywords).

An alternative approach is to pass the integer to a function by reference:

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

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

Output:

8
Frick answered 6/6, 2010 at 19:46 Comment(2)
Neither of these is exactly what OP is asking for, which seems to be (if I understand correctly) some way to store the ref to the local int foo in Main inside the Bar object, such that other method calls on the Bar instance change the value of foo in Main. Not sure that's actually possible in C#, without going into unsafe code...Mithgarthr
@tzaman, the first one is what the OP is asking for, behaviorwise; remember we've replaced Main's use of foo with bar.Value. It's really just manual boxing, though, which the OP suggests he doesn't want.Micropyle
O
-1

You didn't specify you were against unsafe code, so this should work:

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

I've never used pointers in C#, but it appears to work. I'm just not sure what the possible side effects are.

Ori answered 6/6, 2010 at 20:16 Comment(2)
You are explicitly forbidden from doing this. You must never store a reference to a stack pointer like this. If the pointer survives after the stack frame is gone, bad things happen. That's why this pattern is not legal in safe code in the first place! Unsafe code requires you to know what ALL the possible side effects are; that's why it's unsafe.Nyeman
Well I learn something new every day. Thanks for the explanation. :)Ori
M
-1

This doesn't directly answer your question, but can you not just use the System.Collections.BitArray class?

Just wondering if you are "re-inventing the wheel"?

Mexicali answered 7/6, 2010 at 18:11 Comment(1)
please show how to use BitArray in this scenarioGriego

© 2022 - 2024 — McMap. All rights reserved.