Self Test - Value Type vs Reference Type

一個小測驗,請用大腦編譯並執行以下的程式,試著回答Q1-Q7的結果為何?

這個測驗可以檢定你是否對.NET的Value Type與Reference Type已有正確認識。

struct MyStruc 
{
    public string Name;
    public string Data;
    public MyStruc(string name, string data)
    {
        Name = name;
        Data = data;
    }
    public override string ToString()
    {
        return Name + ":" + Data;
    }
}
 
class MyClass
{
    public string Name;
    public string Data;
    public MyClass(string name, string data)
    {
        Name = name;
        Data = data;
    }
    public override string ToString()
    {
        return Name + ":" + Data;
    }
}
 
 
static void Func1(MyClass c)
{
    c.Data = "F1";
}
 
static void Func2(MyClass c)
{
    MyClass c2 = new MyClass("Foo", "F2");
    c = c2;
}
 
static void Func3(ref MyClass c)
{
    c.Data = "F3";
}
 
static void Func4(ref MyClass c)
{
    MyClass c2 = new MyClass("Foo", "F4");
    c = c2;
}
 
 
static void Func5(MyStruc s)
{
    s.Data = "F5";
}
 
static void Func6(MyStruc s)
{
    MyStruc s2 = new MyStruc("Bar", "F6");
    s = s2;
}
 
static void Func7(ref MyStruc s)
{
    s.Data = "F7";
}
 
static void VarTest()
{
    MyClass c = new MyClass("Init", "Null");
    Func1(c);
    Console.WriteLine("Q1=" + c.ToString());
    Func2(c);
    Console.WriteLine("Q2=" + c.ToString());
    Func3(ref c);
    Console.WriteLine("Q3=" + c.ToString());
    Func4(ref c);
    Console.WriteLine("Q4=" + c.ToString());
    MyStruc s = new MyStruc("Init", "Null");
    Func5(s);
    Console.WriteLine("Q5=" + s.ToString());
    Func6(s);
    Console.WriteLine("Q6=" + s.ToString());
    Func7(ref s);
    Console.WriteLine("Q7=" + s.ToString());
    Console.Read();
}

比較容易搞混的地方Func1及Func3,Class是Reference Type,所以不管是以By Value或By Reference的方式將物件變數傳入函數中,函數中存取及變更的都是你傳入的物件本尊,而不是另外複製的複本。但Func2, Func4倒是可以看出By Reference造成傳入函數的變數c有複本及本尊的差別。Structure在.NET中是Value Type,當成參數傳入時,除非用ref宣告By Reference,否則傳入的都是分身。

正確答案:
Q1=Init:F1
Q2=Init:F1
Q3=Init:F3
Q4=Foo:F4
Q5=Init:Null
Q6=Init:Null
Q7=Init:F7

PS:  昨天在寫程式時,遇到了Q2的Scenario,忽然迷惑了一下,就寫了一小段Code來確認,索性稍加修改變成一個小測驗讓大家玩一玩。

Published 19 October 2007 07:20 AM 由 Jeffrey
Filed under: ,


意見

# 阿良 said on 06 November, 2007 08:06 PM

請問c為何沒有被Func2更改

如你所說

class屬reference tyep

不論是by value or by reference

不是都該name=Foo, data=F2嗎

還是我哪裡搞錯了?

多謝賜教

# Jeffrey said on 07 November, 2007 01:05 AM

我把程式改一下(Func2裡用的c更名為tmpVar)

static void Func2(MyClass tmpVar)

{

   MyClass c2 = new MyClass("Foo", "F2");

   tempVar = c2;

}

在Func2中的tmpVar是個只活在Func2裡的變數,當你呼叫Func2(c)時,一開始tempVar與c都指向"Init,F1",但跑過之後的邏輯後,c仍指向"Init,F1",但tmpVar已改指向"Foo,F2",等Func2呼叫結束,tmpVar, "Foo,F2"的生命週期結束,c仍是指向"Init,F1"沒有任何改變。

你的看法呢?

(必要的) 
(必要的) 
(選擇性的)
(必要的) 

請輸入以上的數字:

【請注意】意見送出後可能需要幾分鐘才會出現在網頁上,請耐心等候。

搜尋

Go

<October 2007>
SunMonTueWedThuFriSat
30123456
78910111213
14151617181920
21222324252627
28293031123
45678910
 
RSS
最新回應


BlogLook Score and Rank

Syndication