以下代码无法正常工作:
using System;
using System.Data;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
MyClass cl = new MyClass();
cl.doSomething();
}
}
public class MyClass : BaseClass
{
protected override void doSelect(DataTable dt)
{
dt = null;
}
public void doSomething()
{
base.Fill();
}
}
public class BaseClass
{
private DataTable dtMain = null;
protected virtual void doSelect(DataTable dt)
{
}
protected void Fill()
{
dtMain = new DataTable();
this.doSelect(dtMain);
if (dtMain == null)
Console.WriteLine("as I would expect");
else
Console.WriteLine("why not changed???");
}
}
}
我用其他引用类型测试了它,但行为相同。这是一个框架错误吗?当我使用ref关键字时,它按预期工作:
protected virtual void doSelect(ref DataTable dt)
{
} and so on
很高兴我有人可以帮助我!
答案 0 :(得分:1)
考虑以下
class Program
{
static void Main(string[] args)
{
var pr = new Program();
f(pr);
if (pr == null)
Console.WriteLine("Can't happen");
else
Console.WriteLine("Always happen");
}
public static void f(Program prog)
{
prog = null;
}
}
pr
对某些内存地址的变量引用,比如说0x111111
。
当您拨打f
方法时,实际发生的是,prog
变量被指定为与pr
ei 0x111111
相同的值。
当您将null
分配给prog
变量,它会使prog
变量指向null
但不会pr
变量内容,而0x111111
中存储的内容也不会改变。因此,pr
变量仍引用0x111111
内存地址。你的情况也是如此。
答案 1 :(得分:0)
当不使用ref
关键字时,参数将按值传递。如果您更改值(即引用)以引用其他内容(此处为null
),则不会在调用者方面反映出来。
这与您使用virtual
和override
无关。
此处ref
的替代方法是返回新值(而不是返回void
),如:
protected virtual DataTable doSelect(DataTable dt)
{ /* ... */ }
确保您的方法名称反映了该方法的作用。
答案 2 :(得分:0)
当doSelect()
将null
分配给dt
时,它只会更改其堆栈帧中指针的值。但是,Fill()
拥有自己的堆栈框架,并拥有dtMain
自己的“副本”。 doSelect()
未更改此值。
通过ref
传递值意味着将指针传递给调用者(Fill()
)堆栈框架内的值。
答案 3 :(得分:0)
这不是一个错误。 这是预期的行为。 除非您使用ref关键字,否则您将按值传递,因此方法“客户端”侧的值不会更改。 阅读ref关键字的MS参考: