关于c#:. NET框架bug?

.NET framework bug? Parameter of override method does not change

本问题已经有最佳答案,请猛点这里访问。

以下代码无法按预期工作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
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关键字时,它按我的预期工作:

1
2
3
protected virtual void doSelect(ref DataTable dt)
{
} and so on

如果有人能帮我,那就太好了!


考虑以下内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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相同的值,即0x111111变量。
当您将null分配到prog变量时,它使prog变量指向null但不是pr变量内容,也不是存储在ed中的内容。OCX1〔15〕变更。因此,pr变量仍然引用0x111111内存地址。
同样的情况也会发生在您的案例中。


这不是一个错误。这是预期的行为。除非使用ref关键字,否则将按值传递,因此方法的"客户机"端的值不会更改。读取ref关键字的ms引用:

https://msdn.microsoft.com/en-us/library/14akc2c7.aspx


doSelect()null分配给dt时,它只改变其堆栈帧中指针的值。但是,Fill()有它自己的堆栈帧和它自己的dtMain的"副本"。该值未被doSelect()更改。

通过ref传递一个值意味着在调用方(Fill()堆栈帧内传递一个指向该值的指针。


不使用ref关键字时,参数按值传递。如果您将值(即引用)更改为引用其他内容(此处为null),则不会反映在调用方方面。

这实际上与您使用virtualoverride无关。

这里的ref的一个替代方法是返回新值(而不是返回void),如下所示:

1
2
protected virtual DataTable doSelect(DataTable dt)
{ /* ... */ }

确保您的方法名反映了该方法的作用。