【问题标题】:Hold reference to int in c#在 c# 中保持对 int 的引用
【发布时间】:2014-04-11 05:44:34
【问题描述】:

我有 int 变量让我们说:

int x = 0;

然后我将它传递给应该保存它并且具有打印该变量当前值的 Print 方法的类。

然后在另一个类中我更改了 i 值,因此我希望在调用打印 i 变量的新值后在 MyPrinter 类中打印。有可能吗?

下面的示例代码:

int x = 0;
MyPrinter printer = new MyPrinter(x);
printer.Print(); //Expected result is 0
x++;
MyPrinter.Print(); //Expected result is 1

【问题讨论】:

  • 这是不可能的。
  • 因为没必要又丑?
  • 做不到,我很高兴
  • 为什么,因为这是一个有保证的 bugfest。
  • @user3388684(如果那是你的真名)我认为你对这里的许多评论者/回答者相当不尊重,尽管他们发布了一些相当独特的建议来帮助你。我认为你应该重新考虑你对一个人们无偿贡献时间的网站的态度。

标签: c# .net pass-by-reference


【解决方案1】:

int 被传递给方法或构造函数时,它是按值传递的,被调用者会得到该值的副本。此副本独立于原始副本,因此对一个副本的更新不会反映在另一个副本上。可以通过ref 传递它,但这不适合这里,因为ref 不能用于类型的字段。

为了完成这项工作,您需要将int 值放入class,然后将该类传递给MyPrinter

class Container {
  public int Value;
}

Container x = new Container();
MyPrinter printer = new MyPrinter(x);
printer.Print();
x.Value++;
MyPrint.Print();  // x.Value is 1 

【讨论】:

  • 哦,太好了,所以我必须构建包装类来存储对简单 int 变量的引用。真正干净的解决方案...@Ant P
  • @user3388684 如果您想在堆中存储和共享对int 或任何其他值类型的引用,那么是的,这是唯一的方法。
  • 我写了一个非常好的答案,与这个基本相同(对各种情况下发生的情况有更多解释......)但提交没有提交。跨度>
  • 另外,是否可以只使用Int 而不是制作包装类?
  • @EtherDragon No - Int32int 是一回事。
【解决方案2】:

您可以更改您的课程以使用Func<int> 并关闭x,例如

public class Printer
{
    private readonly Func<int> f;
    public Printer(Func<int> f)
    {
        this.f = f;
    }

    public void Print()
    {
        Console.WriteLine(f());
    }
}


MyPrinter printer = new MyPrinter(() => x);
printer.Print(); //Expected result is 0
x++;
MyPrinter.Print(); //Expected result is 1

【讨论】:

  • 取决于编译器优化,这可能无法按预期工作。
  • @DavidHaney - 哪些编译器优化?
  • 在循环关闭的情况下,这可能会产生意想不到的副作用,需要注意。看起来这段代码可能会出现循环打印,但这只是我的猜测。
  • @DavidHaney 有什么副作用?
  • @JonBarker - C# 5 中的闭包逻辑没有变化。您所指的变化是循环变量始终是 foreach 的本地变量,而不是在外部声明。
【解决方案3】:

正如其他人所指出的,如果不将 int 包装在引用类型中或做一些其他时髦的事情,您就无法做到这一点。

但是,我认为这忽略了重点,即您解决问题的方式完全错误。这是一种更适合 OOP 的方式来解决您的问题:

public class Printer
{
    public int Value { get; set; }

    public Printer(int x)
    {
        Value = x;
    }

    public void Print()
    {
        Console.WriteLine(Value);
    }
}

public class Program
{
    public static void Main()
    {
        var printer = new Printer(0);

        printer.Print();    
        printer.Value++;        
        printer.Print();
    }
}

【讨论】:

  • 不不不,我想要一个类的对象让我们说观察特定的 int 变量并始终打印它的确切值,该值可以从许多不同的地方更改
  • 在 OOP 中这样做的正确方法是使 int 成为 Printer 的属性,然后将 Printer 本身传递给需要操作它的其他类。基本上,你做错了。
  • @user3388684:可以从许多不同位置更改的变量天生就是糟糕的设计,因为您无法始终确定上次更改的位置。不过,这几乎是一样的。
  • @Ant P -> 哈哈。我可以在数百个地方引用打印机,然后就可以了,对吧? pff 别再写无意义的 cmets 了
  • @user3388684(如果那是你的真名)我认为你对这里的许多评论者/回答者相当不尊重,尽管他们发布了一些相当独特的建议来帮助你。我认为你应该重新考虑你对一个人们无偿贡献时间的网站的态度
【解决方案4】:

这是无法做到的,除非您将int 包装在一个引用类型中,以便MyPrinterint 作为对您正在修改的同一对象的引用的一部分。

编辑:@JaredPar 有相同的答案,但有一个干净的代码示例! :)

【讨论】:

    【解决方案5】:

    为了让它工作,你需要传递一个引用类型而不是值类型。实例原语总是按值传递,但没有什么能阻止你传递实例 - 但这需要重新设计你的类:考虑以下(类似 c# 的伪代码)...

    public class Container
    {
        public int x;
    }
    
    ... // some implementation in another class
    Container myContainer = new Container();
    myContainer.x = 0;
    
    MyPrinter printer = new MyPrinter(myContainer);
    printer.Print(); //Result is 0
    myContainer.x ++;
    MyPrinter.Print(); //Result is 1
    

    这假定MyPrinter 类知道如何处理Container 实例。

    这里发生了什么?像int 这样的原语是按值传递的——这意味着程序在将其传递给方法时会进行复制:

    int x = 0;
    MyPrinter printer = new MyPrinter(x); // Makes a copy of x, and passes the copy to MyPrinter
    printer.Print(); //Expected result is 0 - correct
    x++; // Increments the local variable, but not the copy
    MyPrinter.Print(); //Expected result is 1 - incorrect because only the local variable is updated.
    

    相对于:

    Container myContainer = new Container();
    myContainer.x = 0;
    
    MyPrinter printer = new MyPrinter(myContainer); // Passes the reference to the same instance
    printer.Print(); //Result is 0 - because it uses the variable attached to the instance
    myContainer.x ++; // Increments the variable attached to the instance
    MyPrinter.Print(); //Result is 1 - because the instance is still the same in both places - due to being passed by reference.
    

    【讨论】:

    • 哦!它确实提交了......基本上是对上面 JaredPar 答案的扩展。是的,拥有一个公共变量是一个糟糕的主意 - 但目前这与问题并不特别相关。
    • 我知道这太迂腐了,但引用类型在 C# 中也是按值传递的,其中传递的值具有所有相同的引用。差异可能是有意义的,因为即使是整数引用类型也不能在一个地方修改并在另一个地方观察,因为它的重新分配会改变引用。引用类型包装整数展示了您和许多其他人所说的引用类型行为。这就是存在refout 关键字的原因。
    猜你喜欢
    • 1970-01-01
    • 2011-02-25
    • 1970-01-01
    • 1970-01-01
    • 2016-11-14
    • 1970-01-01
    • 2017-08-07
    • 2013-12-11
    • 1970-01-01
    相关资源
    最近更新 更多