none
請教一個觀念問題 RRS feed

  • 問題

  • 我有一個form跟一個usercontrol

    在form load時給s2的值為"123"

    1.按下button1時,debug時a得到的值為"123"

    2.按下button2時,debug時a得到的值為"button1"

    3.按下button1時,debug時a得到的值為"button1"

    當第3點按下button1,s2的值不是應該為"button2",都是用樣一個u2,只是內容改變

    請問是我的理解哪裡有誤了,感謝說明

    public partial class Form4 : Form { private uc2 u2 = new uc2(); public Form4() { InitializeComponent(); } private void Form4_Load(object sender, EventArgs e) { u2.s2 = "123"; panel1.Controls.Add(u2); } private void button1_Click(object sender, EventArgs e) { string a = u2.s2; u2 = new uc2(); u2.s2 = "button1"; panel1.Controls.Clear(); panel1.Controls.Add(u2); } private void button2_Click(object sender, EventArgs e) { LoadControl(panel1, u2); } private void LoadControl(Panel p, uc2 uc) { string a = uc.s2; uc = new uc2(); uc.s2 = "button2"; p.Controls.Clear(); p.Controls.Add(uc); } }

     public partial class uc2 : UserControl
        {        
            public string s2 { set; get; }
            public uc2()
            {
                InitializeComponent();
            }
          
            private void uc2_Load(object sender, EventArgs e)
            {
                label1.Text = s2;
            }
        }


    2013年10月16日 上午 05:02

解答

  • (1) 對參考型別而言 執行個體(物件) 和 物件變數是兩件事

    (2) 從你程式碼來分析 (以下是簡化過很多事情的說法)

    (2-1) private uc2 u2 = new uc2(); 

    你建立了一個變數叫 u2 (我們假設這個變數在記憶體位址 0XFF00) , 這個變數 u2 指向一個由 uc2 類別產生的實體 (我們假設給他個名字叫  objUC2-1(實際是沒有這個東西, 只是為了說明方便) 好了 , 並假設這個實體存在的記憶體位址為  08X0020)

    (2-2) 所以 u2 這個變數中, 儲存的其中有一樣就是 objUC2-1 的位址, 也就是在 u2 變數的內容是 08X0020

    (2-3) 在 form load 中你指派了一個 "123" 給 objUC2-1 (08X0020) 的 s2 屬性

    (2-4) 第一次 click button1 ,

    這時的 a 指向 obj2UC2-1 的 s2 屬性的位址 (因為 s2 是 string, 很不巧也是參考型別), 而這個位址的內容是字串"123"

    然後你執行了 u2= new uc2(); 這時位於 0xFF00 的變數 u2 就指向新的 uc2 實體 (假設名字為 objUC2-2, 位址在 08X0080)

    這代表此時 u2 變數的內容值是 08X0080, 然後你給了 objUC2-2 這個物件的屬性 s2 的值為 "button1" (實際上是 s2 指向 "button1" 字串所在的位址)

    (2-5) 然後是 click button2 , 你在這邊呼叫了 LoadControl 方法, 並且將 u2 變數以傳值 (by value) 的方式船過去給 LoadControl 方法 (參數名稱叫  uc), 那在 LoadControl 方法中的行為是產生一個新的變數叫 uc, u2 將其內容傳給 uc,

    所以此時 uc 這個變數本身會佔據另一塊記憶體 (假設是 0XFFAA), 其變數的內容值是 08X0080 (因為從 u2 傳過來)

    看出來沒有 uc 和 u2 是兩個變數, 只是目前內容指向同一個實體 objUC-2.

    接者你又再度 uc= new uc2(); 和先前一樣, 他又產生第三個  uc2 類別實體, 所以又占了另一個記憶體 , 假設為 08XEE00

    這時 uc 的內容值就變成了 08XEE00 , 所以不論 uc 變數本身所在的位址, 或是其所指向的物件, 都和 u2 與 objUC-2 完全無關了

    (2-6) 接下來的推論你就應該懂了吧.


    在現實生活中,你和誰在一起的確很重要,甚至能改變你的成長軌跡,決定你的人生成敗。 和什麼樣的人在一起,就會有什麼樣的人生。 和勤奮的人在一起,你不會懶惰; 和積極的人在一起,你不會消沈; 與智者同行,你會不同凡響; 與高人為伍,你能登上巔峰。 <br/> <a target="_blank" href="http://www.bplan.com.tw/chunfeng/front/bin/ptlist.phtml?Category=103591"><img border="0" src="http://files.dotblogs.com.tw/billchung/1007/20107414497912.gif" width="200" height="67"></a>

    • 已提議為解答 小朱MVP, Moderator 2013年10月16日 下午 04:02
    • 已標示為解答 KK945 2013年10月17日 上午 01:53
    2013年10月16日 上午 09:59
    版主

所有回覆

  • Hi,

    你這樣塞不會是塞到全域變數,另外你的程式這樣一直這樣new出control一直去重塞不是很好,會有過多不必要的記憶體耗費,效能也會受影響,程式碼也不好維護。

            private void LoadControl(Panel p, uc2 uc)
            {
                string a = uc.s2;
                uc = new uc2(); // <= Here is wrong
                uc.s2 = "button2";
                p.Controls.Clear();
                p.Controls.Add(uc);
            }



    謙卑學習,持之以恆,才能不斷的Level Up


    2013年10月16日 上午 06:07
  • 因為LoadControl方法中使用uc變數管理新建立的物件, 而不是用u2變數管理新建立的物件之故, 因此原u2變數管理的物件的s2的內容值仍為button1
    2013年10月16日 上午 07:44
  • 您好

    只是測試而已,實際沒有一直new新物件

    目前我是加一個方法去重新整理usercontrol

    2013年10月16日 上午 08:44
  • 因為LoadControl方法中使用uc變數管理新建立的物件, 而不是用u2變數管理新建立的物件之故, 因此原u2變數管理的物件的s2的內容值仍為button1
    您好
    但我LoadControl中的uc變數是指定u2帶進去的,這樣也會產生另一個不同u2的control?
    2013年10月16日 上午 08:48
  • 您好,

    Larry Nung(蹂躪) 有說雖然把u2傳進去,但您有重新new uc2哦!

    另外,您一開始就建立了u2這個全域變數了(private uc2 u2 = new uc2();) !

    所以之後應該是不需要在重新加入panel時,再new一個uc2哦!

    如下,

    public partial class uc2 : UserControl
    {
    	public uc2()
    	{
    		InitializeComponent();
    	}
    
    	private string _s2;
    	public string s2 { 
    		set {
    			_s2 = value;
    			label1.Text = value;
    		}
    		get { 
    			return _s2; 
    		}
    	}
    	private void uc2_Load(object sender, EventArgs e)
    	{
    		//label1.Text = s2;
    	}
    }
    private void Form4_Load(object sender, EventArgs e)
    {
    	u2.s2 = "123";
    	panel1.Controls.Add(u2);
    }
    
    private void button1_Click(object sender, EventArgs e)
    {
    	string a = u2.s2;
    	//u2 = new uc2();
    	u2.s2 = "button1";
    	panel1.Controls.Clear();
    	panel1.Controls.Add(u2);
    }
    
    private void LoadControl(Panel p, uc2 uc)
    {
    	string a = uc.s2;
    	//uc = new uc2();
    	uc.s2 = "button2";
    	p.Controls.Clear();
    	p.Controls.Add(uc);
    }
    
    private void button2_Click(object sender, EventArgs e)
    {
    	LoadControl(panel1, u2);
    }
    



    亂馬客blog: http://www.dotblogs.com.tw/rainmaker/

    2013年10月16日 上午 09:20
  • (1) 對參考型別而言 執行個體(物件) 和 物件變數是兩件事

    (2) 從你程式碼來分析 (以下是簡化過很多事情的說法)

    (2-1) private uc2 u2 = new uc2(); 

    你建立了一個變數叫 u2 (我們假設這個變數在記憶體位址 0XFF00) , 這個變數 u2 指向一個由 uc2 類別產生的實體 (我們假設給他個名字叫  objUC2-1(實際是沒有這個東西, 只是為了說明方便) 好了 , 並假設這個實體存在的記憶體位址為  08X0020)

    (2-2) 所以 u2 這個變數中, 儲存的其中有一樣就是 objUC2-1 的位址, 也就是在 u2 變數的內容是 08X0020

    (2-3) 在 form load 中你指派了一個 "123" 給 objUC2-1 (08X0020) 的 s2 屬性

    (2-4) 第一次 click button1 ,

    這時的 a 指向 obj2UC2-1 的 s2 屬性的位址 (因為 s2 是 string, 很不巧也是參考型別), 而這個位址的內容是字串"123"

    然後你執行了 u2= new uc2(); 這時位於 0xFF00 的變數 u2 就指向新的 uc2 實體 (假設名字為 objUC2-2, 位址在 08X0080)

    這代表此時 u2 變數的內容值是 08X0080, 然後你給了 objUC2-2 這個物件的屬性 s2 的值為 "button1" (實際上是 s2 指向 "button1" 字串所在的位址)

    (2-5) 然後是 click button2 , 你在這邊呼叫了 LoadControl 方法, 並且將 u2 變數以傳值 (by value) 的方式船過去給 LoadControl 方法 (參數名稱叫  uc), 那在 LoadControl 方法中的行為是產生一個新的變數叫 uc, u2 將其內容傳給 uc,

    所以此時 uc 這個變數本身會佔據另一塊記憶體 (假設是 0XFFAA), 其變數的內容值是 08X0080 (因為從 u2 傳過來)

    看出來沒有 uc 和 u2 是兩個變數, 只是目前內容指向同一個實體 objUC-2.

    接者你又再度 uc= new uc2(); 和先前一樣, 他又產生第三個  uc2 類別實體, 所以又占了另一個記憶體 , 假設為 08XEE00

    這時 uc 的內容值就變成了 08XEE00 , 所以不論 uc 變數本身所在的位址, 或是其所指向的物件, 都和 u2 與 objUC-2 完全無關了

    (2-6) 接下來的推論你就應該懂了吧.


    在現實生活中,你和誰在一起的確很重要,甚至能改變你的成長軌跡,決定你的人生成敗。 和什麼樣的人在一起,就會有什麼樣的人生。 和勤奮的人在一起,你不會懶惰; 和積極的人在一起,你不會消沈; 與智者同行,你會不同凡響; 與高人為伍,你能登上巔峰。 <br/> <a target="_blank" href="http://www.bplan.com.tw/chunfeng/front/bin/ptlist.phtml?Category=103591"><img border="0" src="http://files.dotblogs.com.tw/billchung/1007/20107414497912.gif" width="200" height="67"></a>

    • 已提議為解答 小朱MVP, Moderator 2013年10月16日 下午 04:02
    • 已標示為解答 KK945 2013年10月17日 上午 01:53
    2013年10月16日 上午 09:59
    版主
  • 您好,

    Larry Nung(蹂躪) 有說雖然把u2傳進去,但您有重新new uc2哦!

    Hi,

    澄清一下,我的重點是第一段,非後面new物件那邊。

    重新new是效能跟維護的問題,因為Button1也是New出來清掉重塞,所以這不是造成運行不對的點。

    我說的是塞的地方不對,Button1用的是全域變數指到的物件,LoadControl這邊是改另外一個變數,雖然一開始指的是同一物件,但後續重塞了,兩個變數指到的就是不同的物件實體,而非發問者所預期的要改到全域變數指到的物件。


    謙卑學習,持之以恆,才能不斷的Level Up

    2013年10月16日 上午 10:34
  • 我也認為這個問題的重點根本不是甚麼 new 不 new 的事情.

    這問題其實問得很不錯, 也很有趣, 他正好點出兩個很重要的事情

    (1) 參考型別的 執行個體 與 變數的關係

    (2) 參考型別參數傳值與傳址的差異 (如果今天參數是byref , 那又是另一種結果了)


    在現實生活中,你和誰在一起的確很重要,甚至能改變你的成長軌跡,決定你的人生成敗。 和什麼樣的人在一起,就會有什麼樣的人生。 和勤奮的人在一起,你不會懶惰; 和積極的人在一起,你不會消沈; 與智者同行,你會不同凡響; 與高人為伍,你能登上巔峰。 <br/> <a target="_blank" href="http://www.bplan.com.tw/chunfeng/front/bin/ptlist.phtml?Category=103591"><img border="0" src="http://files.dotblogs.com.tw/billchung/1007/20107414497912.gif" width="200" height="67"></a>

    2013年10月16日 下午 01:51
    版主
  • 謝謝小朱版主詳細說明

    也謝謝各位先進回覆

    2013年10月17日 上午 03:06
  • 我一個字都沒說吧... 

    強力監督SQL Injection問題!!

      • 小朱的技術隨手寫:http://www.dotblogs.com.tw/regionbbs/
      • 雲端學堂Facebook: http://www.facebook.com/studyazure

    2013年10月17日 上午 05:12
    版主
  • 我一個字都沒說吧... 

    對不起,是我看錯了,是您提議為解答

    是比爾才對

    2013年10月17日 上午 07:57