【问题标题】:C# Instance copy / Passing object reference is different then Java?C# 实例复制/传递对象引用与 Java 不同?
【发布时间】:2011-06-25 20:52:11
【问题描述】:
class Player
{
   private Location location;

   public Location getLocation()
   {
        return location;
   }

    public void setLocation(Location location)
    {
        this.location = location;
    }
}

...

class Location
{
    int x,y,z;

    public Location(int x, int y, int z)
    {
        this.x = x;
        this.y = y;
        this.z = z;
    }

    public Location(Location location)
    {
        this.x = location.x;
        this.y = location.y;
        this.z = location.z;
    }


    public void updateLocation(Location location) //the fix..
    {
        this.x = location.x;
        this.y = location.y;
        this.z = location.z;
    }
}

说..你愿意

Player p1 = new Player();
Player p2 = new Player();
p1.setLocation(p2.getLocation());

现在当您尝试修改其他人的位置时会出现错误/问题。两个玩家的位置变化完全相同,因为他们现在共享相同的位置。

所以当然下面的就可以了。

p1.setLocation(new Location(p2.getLocation()));

但问题是它总是创建一个新对象..当我可以更新现有实例时..?如何在默认情况下更新现有实例,而无需像下面那样创建自己的方法来解决此问题。

我必须使用下面的方法来解决这个问题(默认情况下,任何方式都可以做到这一点,而不是像下面这样)

    public void setLocation(Location location)
    {
        if (this.location == null)
            this.location= new Location(location);
        else
            this.location.updateLocation(location);
    }

有人知道我可能不知道的技巧吗?谢谢。

【问题讨论】:

  • 您可以将Location 设为结构。然后,它将按值传递。这将起作用,因为您的位置对象基本上是其他值类型的容器,并且相对较小。
  • 它还有其他方法,如 .Equals() 和 .withinDistance(other Location) 等。
  • 您可以将成员添加到结构中。只需保持较小,并记住结构越大,它在堆栈上占用的内存就越多。这是 msdn 的 C# 结构体编程指南链接:msdn.microsoft.com/en-us/library/saxz13w4(v=VS.90).aspx
  • 只是与您的问题无关的注释:在 C# 中,您应该使用属性,而不是类似 Java 的 get 和 set 方法。
  • 为什么每次出现问题都要创建一个新对象?

标签: c# visual-studio multiple-instances default-copy-constructor


【解决方案1】:

类是引用类型。当你调用它时:

p1.setLocation(p2.getLocation());

您不是将实例数据传递给方法,而是传递对实例的引用。引用就像指向存储实例数据的堆(内存)的托管指针。这非常重要,因为否则对实例数据的所有更改都只有方法范围。当你调用它时:

this.location = location;

您分配的是参考而不是数据。这意味着locationthis.location 都会指向内存中的同一个块。

这是 C# 编程的要点。如果您希望复制数据而不是引用数据,则必须使用结构而不是类。

无论如何,将值从一个实例重新分配到另一个实例是很常见的任务。

编辑:

您指出您不想因为开销而创建新对象。

  • 过早的优化是万恶之源
  • 优化有意义的地方以及真正导致性能下降的地方。 Here 您对简单笔记本电脑上的对象实例化有一些看法。

还说你不喜欢属性很奇怪——你是用 C# 编程的,所以要正确使用它,否则你的同事不会喜欢你。

【讨论】:

  • 当然在那个链接中他在一秒钟内创建了 700 万个对象,但是当垃圾收集器出现时 CPU 会飙升会发生什么?
  • 7M 只是第一个被StopWatch 评估减慢的测试。评论中的最后一个测试能够达到450M。 GC 影响是一个单独的故事,属于我的第一点 - 遇到问题时进行优化。您可以确定您的代码将包含更糟糕的部分。
  • 是的,谢谢,在产品完成之前我会避免优化。关于属性,使用它们感觉很奇怪,它们感觉像是变量,这是一个很大的优势..但是当你设置它们时..你不能物理设置它..你必须将它设置在一个对我来说非常混乱的支持变量上。虽然这正是我使用 java/c/c++ 风格的函数/方法调用所做的事情。至少我知道那些是具有属性的方法/函数,这很奇怪。
  • 你见过auto properties吗?
  • 是的,忘了提..这很好,但我该怎么做这样的事情..(都在同一范围内)public string X { get; set { doSomething(value); this = value; //? X = value; //? } } 当我使用this 时,我并不暗示该类它所在的地方我的意思是实际的财产(只是乱七八糟)
【解决方案2】:

在 .NET 中传递引用与 Java 基本相同。但是.NET 我们有一些额外的功能。

例如 out 和 ref 参数可用于返回作为参数传递的值。例如

    public void SaveProductFeature(ref SaveCollection save)
    {
       SaveCollection.Product.ProductId = Product.Save(SaveCollection.Product);
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-01-15
    • 1970-01-01
    • 2016-12-27
    • 2021-04-01
    • 2016-06-05
    • 1970-01-01
    相关资源
    最近更新 更多