我尝试使用下面的代码,我得到输出为1000.我听说分配对象必须共享引用而不是复制整个对象内存。结果不同。任何人都可以提供帮助。
public aaaaa ad = new aaaaa();
static void Main(string[] args)
{
Program p = new Program();
p.fun1();
p.fun2();
}
public void fun1()
{
using(smallclass s = new smallclass())
{
s.j = 1000;
ad.fun1(s);
}
}
public void fun2()
{
ad.fun2();
}
public class aaaaa
{
public smallclass h = new smallclass();
public void fun1(smallclass d)
{
h = d;
}
public void fun2()
{
Console.WriteLine(h.j);
}
}
public class smallclass:IDisposable
{
public int j = 9;
public void Dispose()
{
GC.SuppressFinalize(this);
}
}
更新: 我期待一个对象引用异常,因为引用的内存放在p.fun1();
中答案 0 :(得分:2)
不,assingning不是一个“新”语句,它复制....一个引用,它不会创建一个新对象。对于一个班级。
对于结构体,它会这样做。
我建议通过阅读文档或书籍来学习C# - 这些基础知识通常会在这些基础知识中得到很好的处理。
答案 1 :(得分:2)
这是一个简单的例子,如何协助工作
using System;
namespace ConsoleApplication1
{
internal class Program
{
private static smallclass objA = new smallclass();
private static smallclass objB = new smallclass();
private static void Main(string[] args)
{
showValues();
objA.value = 1000;
showValues();
objB = objA;
showValues();
objA.value = 1055;
showValues();
}
private static void showValues()
{
Console.WriteLine("objA.value: " + objA.value);
Console.WriteLine("objB.value: " + objB.value);
Console.ReadLine();
}
}
internal class smallclass : IDisposable
{
public int value = 0;
public void Dispose()
{
//Here you can remove eventHandlers
//or do some other stuff before the GC will play with it
}
}
}
就像你看到的那样
首先我们创建2个对象objA
和objB
比我们显示的预期值都是0
之后我们将objA
的值增加到1000
objA
a的值为1000,objB
的值保持为0
现在我们正在协助objA
和objB
所以objB
的值也得到了1000
如果我们现在将objA
的值更改为1055
objB
的值也变了
因为objB
不再是一个单独的对象,它现在保持不变
像objA
这样的引用
现在我将向您展示如何根据您的示例获取错误
将您的aaaaa class
更改为:
public class aaaaa
{
public WeakReference<smallclass> h;
public void fun1(smallclass d)
{
h = new WeakReference<smallclass>(d);
}
public void fun2()
{
smallclass k;
if(h.TryGetTarget(out k))
Console.WriteLine(k.j);
else
Console.WriteLine("ERROR ERRROR ERROR");
}
}
并将您的static void Main(string[] args)
修改为:
static void Main(string[] args)
{
Program p = new Program();
p.fun1();
GC.Collect();
p.fun2();
Console.Read();
}
好的,让我们完成修改
我们正在使用WeakReference<T>
(您也可以使用WeakReference)
如果GC现在遇到我们的对象,他找不到StrongReference,所以可以收集它
现在到GC.Collect()
你需要调用它,因为它迫使GC完成他的工作(现在此时)
并且记得就像我之前告诉你的那样IDisposable会在他破坏对象(AFAIK)之前从GC调用它,所以在对象被破坏之前有地方可以放置所有需要完成的东西
答案 2 :(得分:1)
如果你想到每个引用类型变量,字段,参数,数组插槽或其他此类存储位置,持有“null”或“object#24601”[或其他一些数字],你就不会出错。实际上只有少数事情可以用引用来完成:
您可以创建空引用
您可以要求系统创建一个新对象并返回对它的引用
您可以将一个引用复制到另一个
您可以检查两个引用是否彼此相等,或者一个引用是否等于null。
您可以要求系统对引用标识的对象执行某些操作
如果myCar
是某个引用类型的变量,则myCar.Color = CarColors.Blue
之类的语句根本不会影响变量myCar
。相反,它会观察到myCar
持有[例如]“对象#8675309”,然后要求系统访问对象#8675309的Color
属性或字段。相反,如果otherCar
碰巧持有“对象#90210”,则otherCar=myCar
形式的语句将不会对对象#8675309执行任何操作,也不对对象#90210执行任何操作,而是替换“90210”存储在otherCar
中,带有“8675309”。
对象保证存在,只要存在任何形式的引用,但是如果有两个对象虽然彼此引用,但未被引用通过宇宙中的任何其他东西,两个对象可能同时不复存在。这条规则是绝对的,但有一些曲折:代码可能会向对象请求WeakReference
;只要存在对它的弱引用,就保证存在一个对象,但是如果系统发现没有对某个对象的强引用,它将使每个WeakReference
无效。此外,系统保留所有想要在被放弃时通知的对象的列表。如果系统发现此列表包含对象的唯一引用,则它会将对象移动到强引用的对象列表,其Finalize
方法应在第一个方便的机会运行。运行对象的Finalize
方法时,将从后一个列表中删除引用。如果在同一时间内没有对对象的引用存储,该对象将不再存在。
答案 3 :(得分:0)
我已经在dispose函数中用GC.Collect()替换了GC.SuppressFinalize,但这并没有释放内存..并且结果是收到1000。
我猜,因为它拥有其他引用(变量h),即使我们显式调用它,GC也不会释放内存。
因此,我们可以很好地传递和分配对象,而不管分配的(新)对象是否超出范围。
如果我错了,请纠正我。