如何在C#中存储整数的引用?

12

可能是重复问题:
如何在C#中将引用分配给类字段?

大家好 - 告诉我如何使这个工作?基本上,我需要一个整数引用类型(在C++中可以使用int*)

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,只需引用所需的整数即可。

1
你的目标是什么?这基本上违背了托管代码的整个理念;如果你可以在某个与 main 生命周期无关的其他类中存储对 foo 的引用,那么当 main 退出并且包含 foo 的堆栈帧被销毁时会发生什么? - tzaman
@tzaman,我的编辑是否澄清了我的意图? @abatishchev - 我想这样做,但是两个答案都没有完全符合我的要求。也许这是不可能的。 - Jonathon Reinhart
为什么不使用不安全指针来实现你想要的功能呢?你甚至提到如果这是在C++中,指针就可以解决问题。 - David Brown
这是 https://dev59.com/iHA85IYBdhLWcg3wBOxO#2982037 的副本。请查看我的答案,了解为什么无法将变量的引用存储在字段中以及绕过该限制的方法。 - Eric Lippert
是的,我想我现在明白你想做什么了。我已经回答了一个实现这个目标的方法。 - tzaman
4个回答

7
您不能直接存储对整数的引用,但是您可以存储包含该整数的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);
            }
    }
    }
}

谢谢!这正是我在寻找的。而且你的BitAccessor看起来和我写的一模一样。 唯一更好的事情是能够将其应用于任何整数 - 但这不能在没有引用的情况下完成。然而,你的解决方案对于我的项目范围来说已经很好了。 - Jonathon Reinhart
你也可以添加这个: public static implicit operator GlorifiedInt(int v) { return new GlorifiedInt(v); }这使得你可以这样写: 例如 GlorifiedInt a = 10; - Aidan

4

你不需要引用一个整数 - 只需将你的整数放在一个引用类型中 - 这几乎就是你已经做过的事情。只需更改此行:

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

2
这两种方法都不完全符合 OP 所要求的,OP 貌似是想(如果我理解正确的话)找到一种方法来存储 Main 中本地变量 int foo 的引用到 Bar 对象中,以便在 Bar 实例上的其他方法调用会更改 Main 中的 foo 值。不确定在 C# 中是否实际可行,除非使用不安全的代码... - tzaman
@tzaman,第一个是OP所要求的行为;请记住我们已经用bar.Value替换了Main中对foo的使用。但实际上这只是手动装箱,而OP则表示他不想要这种方法。 - user24359

-1

你没有说明你反对不安全的代码,所以这应该可以工作:

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#中使用过指针,但它似乎可以工作。我只是不确定可能的副作用是什么。


11
你被明确禁止这样做。你必须永远不要像这样存储指向堆栈指针的引用。如果指针在堆栈帧消失后仍然存在,会发生糟糕的事情。这就是为什么这种模式在安全代码中根本不合法!不安全的代码要求你知道所有可能的副作用;这就是为什么它是不安全的原因。 - Eric Lippert
每天我都会学到新的东西。谢谢你的解释。:) - David Brown

-1

这并不直接回答你的问题,但是你能否使用System.Collections.BitArray类呢?

只是好奇你是否在“重复造轮子”?


请展示如何在这种情况下使用 BitArray。 - gdbdable

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接