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.

Community
  • 1
  • 1
Jonathon Reinhart
  • 132,704
  • 33
  • 254
  • 328
  • 1
    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? – tzaman Jun 06 '10 at 19:59
  • @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. – Jonathon Reinhart Jun 06 '10 at 22:56
  • Why wouldn't unsafe pointers do what you're looking for? You even mentioned pointers would do the trick if this were in C++. – David Brown Jun 07 '10 at 00:44
  • yeah, I think I see what you're trying to do now. I've answered with a way to do just that. – tzaman Jun 07 '10 at 05:37
  • This is a duplicate of https://stackoverflow.com/questions/2980463/how-do-i-assign-by-reference-to-a-class-field-in-c/2982037#2982037 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. – Eric Lippert Jun 07 '10 at 01:44

4 Answers4

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);
            }
    }
    }
}
tzaman
  • 46,925
  • 11
  • 90
  • 115
  • 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. – Jonathon Reinhart Jun 18 '10 at 03:57
  • 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; – Aidan Feb 15 '18 at 13:15
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
Mark Byers
  • 811,555
  • 193
  • 1,581
  • 1,452
  • 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... – tzaman Jun 06 '10 at 19:58
  • @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. –  Jun 06 '10 at 20:30
-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.

David Brown
  • 35,411
  • 11
  • 83
  • 132
  • 11
    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.** – Eric Lippert Jun 07 '10 at 01:51
  • Well I learn something new every day. Thanks for the explanation. :) – David Brown Jun 07 '10 at 03:20
-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"?

Chris Dunaway
  • 10,974
  • 4
  • 36
  • 48