跳到主要內容

 none
改變類別對像 RRS feed

  • 問題

  • 請問!

    如果有 class a, b, c 這三個類別不同但相似, 我用 class A, B, C 將之包裝起來成為有相同介面的類別!

    我在 Form 中, 

    A myclass = new A();

    然後我就可以,

    myclass.function1();

    myclass.function2();

    我想問的是, 我可以在Form中, 設定一個combbox去"動態選擇"我要連結class A, B 或 C 嗎? 一個時間, 只連結一個類別!

    謝謝!

    2019年10月2日 下午 03:04

解答

  • (1) 我覺得你擔心浪費記憶體可能多慮了,事實上如果是幾個類別快速切換,快速且不斷地讓物件新生--死亡反而讓 GC 更忙。

    (2) 如果以你的描述,其實 MyForm 應該持有 Class A, B , C … 的共同抽象,當然前提是他們的事件與方法簽章是相同的,也就是可以設計在共同抽象上。

    (3) 不是很確切了解你所有的情境,以下的範例程式我儘量用簡單點的方式實現:

    先建立相關的抽象 BaseClass 與實作類別 CA,CB

      public abstract class BaseClass
        {
            public string Name
            {
                get { return this.GetType().Name; }
            }
            public event EventHandler XChanged;
    
            public abstract void Exec1();
    
            public abstract void Exec2();
    
    
            private int _x;
    
            // 為了測試事件用的屬性,此屬性值改變將引發 XChanged event
    
            public int X
            {
                get
                {
                    return _x;
                }
                set
                {
                    if (_x != value)
                    {
                        _x = value;
                        XChanged?.Invoke(this, EventArgs.Empty);
                    }
                }
            }
        }
    
    
    
        class CA : BaseClass
        {
    
           
            public override void Exec1()
            {
              Debug.WriteLine($"{Name}-- {nameof(Exec1)}");
                // .. 做點其他不一樣的事 , 假設各類別這個方法實作內容差異很大
            }
    
            public override void Exec2()
            {
                Debug.WriteLine($"{Name}-- {nameof(Exec2)}");
                // .. 做點其他不一樣的事 , 假設各類別這個方法實作內容差異很大
            }
        }
    
        class CB : BaseClass
        {
          
    
            public override void Exec1()
            {
                Debug.WriteLine($"{Name}-- {nameof(Exec1)}");
                // .. 做點其他不一樣的事 , 假設各類別這個方法實作內容差異很大
            }
    
            public override void Exec2()
            {
                Debug.WriteLine($"{Name}-- {nameof(Exec2)}");
                // .. 做點其他不一樣的事 , 假設各類別這個方法實作內容差異很大
            }
        }

    Form1 上的程式碼

       public partial class Form1 : Form
        {
            List<BaseClass> _list;
    
            BaseClass _current;
    
            public Form1()
            {
                InitializeComponent();
                _list = new List<BaseClass>()
                {
                    new CA (),
                    new CB()
                };
            }
    
    
            private void Form1_Load(object sender, EventArgs e)
            {
                comboBox1.SelectedIndexChanged += ComboBox1_SelectedIndexChanged;
                comboBox1.DisplayMember = "Name"; 
                comboBox1.DataSource = _list;            
                
              
    
    
            }
    
            private void ComboBox1_SelectedIndexChanged(object sender, EventArgs e)
            {
               
                if (comboBox1.SelectedIndex > -1)
                {
                    if (_current != null)
                    {
                        _current.XChanged -= OnCurrentXchanged; 
                    }
                    _current = _list[comboBox1.SelectedIndex];
                    _current.XChanged += OnCurrentXchanged;
                }
            }
    
            private void OnCurrentXchanged(object sender, EventArgs e)
            {
                Debug.WriteLine($"引發事件的物件是 {sender.GetType().Name }");
            }
    
            private void button1_Click(object sender, EventArgs e)
            {
                if (_current != null)
                {
                    _current.Exec1();
                }
    
                // 若要簡化,而且 C# 版本支援 ( >= 6.0) 的話可以寫成下方形式
               //  _current?.Exec1();
            }
    
            private void button2_Click(object sender, EventArgs e)
            {
                if (_current != null)
                {
                    _current.Exec2();
                }
                // 若要簡化,而且 C# 版本支援 ( >= 6.0) 的話可以寫成下方形式
                //  _current?.Exec2();
            }
    
            private void button3_Click(object sender, EventArgs e)
            {
                _current.X++;
            }
        }


    在現實生活中,你和誰在一起的確很重要,甚至能改變你的成長軌跡,決定你的人生成敗。 和什麼樣的人在一起,就會有什麼樣的人生。 和勤奮的人在一起,你不會懶惰; 和積極的人在一起,你不會消沈; 與智者同行,你會不同凡響; 與高人為伍,你能登上巔峰。 https://skilltree.my/

    • 已標示為解答 GaryChiang 2019年10月6日 下午 02:20
    2019年10月4日 下午 05:16
    版主

所有回覆

  • 您可以利用程式碼設定ComboBox的Items屬性即可
    2019年10月2日 下午 10:20
  • 我可能沒說的很清楚!

    我的Form在初始化時, 會 new 出一個 class A, 在Form裏的class A的event, delegate也設定好了! 這些東西, 在我的 control(combobox) 被選擇之前都完成了!

    我可以把class A Dispose, 然後 new class B, 用相同的名稱, 然後form裏的一切都不動, 就可以使用了? 如下例

    class A

    {

      public event aEventhandle onEventHappen;

      function1() {........}

      function2() {.........}

    }

    class B

    {

      public event aEventhandle onEventHappen;

      function1() {........}

      function2() {.........}

    }

    class myform

    {

        public A myclass = new A();

        myform()

       {

           myclass.onEventHappen += OnEventHappend;

       }

       OnEventHappend(object o, evnetargs e){  ........... }

        DoSomething1(){ myclass.function1(); }

        DoSomething2(){ myclass.function2(); }

        

        combobox_selected_changed(object o, eventargs e)

        {   //這段是我假設的情況, 我能不動其它部份, 直接更改連結的類別對像

             myclass.dispose();

             public B myclass = new B();

         } 

    }

    謝謝!

    2019年10月3日 上午 02:55
  • 您也可以在MyForm同時建立ClassA和ClassB的物件, 再切換來使用即可, 不用再做Dispose和new


    • 已編輯 tihsMVP 2019年10月3日 上午 10:48
    2019年10月3日 上午 10:48
  • 你好!

    我只舉例了二個類別, 事實上, 程式裏會有6-7個相類似的類別!而在一個時間內, 只會有一個物件被使用! 因此, 把它們都建立, 一來會浪費不少記憶體!二來必需有6-7倍相同程式在 Form 裏面, 增加了不少維護的成本!

    我想到了一個方法, 就是在 Form 裏建立一堆的 delegate , 然後, 看目前使用那一個物件 ,就把它物件化(new), 接著把它的函式全都綁上委派, 由委派來執行, 這樣不知道是否就可以了!?

    由此延伸, C# 的物件沒有委派這個功能嗎? 如果有, 是不是比較方便了!

    謝謝! 


    2019年10月4日 上午 12:40
  • (1) 我覺得你擔心浪費記憶體可能多慮了,事實上如果是幾個類別快速切換,快速且不斷地讓物件新生--死亡反而讓 GC 更忙。

    (2) 如果以你的描述,其實 MyForm 應該持有 Class A, B , C … 的共同抽象,當然前提是他們的事件與方法簽章是相同的,也就是可以設計在共同抽象上。

    (3) 不是很確切了解你所有的情境,以下的範例程式我儘量用簡單點的方式實現:

    先建立相關的抽象 BaseClass 與實作類別 CA,CB

      public abstract class BaseClass
        {
            public string Name
            {
                get { return this.GetType().Name; }
            }
            public event EventHandler XChanged;
    
            public abstract void Exec1();
    
            public abstract void Exec2();
    
    
            private int _x;
    
            // 為了測試事件用的屬性,此屬性值改變將引發 XChanged event
    
            public int X
            {
                get
                {
                    return _x;
                }
                set
                {
                    if (_x != value)
                    {
                        _x = value;
                        XChanged?.Invoke(this, EventArgs.Empty);
                    }
                }
            }
        }
    
    
    
        class CA : BaseClass
        {
    
           
            public override void Exec1()
            {
              Debug.WriteLine($"{Name}-- {nameof(Exec1)}");
                // .. 做點其他不一樣的事 , 假設各類別這個方法實作內容差異很大
            }
    
            public override void Exec2()
            {
                Debug.WriteLine($"{Name}-- {nameof(Exec2)}");
                // .. 做點其他不一樣的事 , 假設各類別這個方法實作內容差異很大
            }
        }
    
        class CB : BaseClass
        {
          
    
            public override void Exec1()
            {
                Debug.WriteLine($"{Name}-- {nameof(Exec1)}");
                // .. 做點其他不一樣的事 , 假設各類別這個方法實作內容差異很大
            }
    
            public override void Exec2()
            {
                Debug.WriteLine($"{Name}-- {nameof(Exec2)}");
                // .. 做點其他不一樣的事 , 假設各類別這個方法實作內容差異很大
            }
        }

    Form1 上的程式碼

       public partial class Form1 : Form
        {
            List<BaseClass> _list;
    
            BaseClass _current;
    
            public Form1()
            {
                InitializeComponent();
                _list = new List<BaseClass>()
                {
                    new CA (),
                    new CB()
                };
            }
    
    
            private void Form1_Load(object sender, EventArgs e)
            {
                comboBox1.SelectedIndexChanged += ComboBox1_SelectedIndexChanged;
                comboBox1.DisplayMember = "Name"; 
                comboBox1.DataSource = _list;            
                
              
    
    
            }
    
            private void ComboBox1_SelectedIndexChanged(object sender, EventArgs e)
            {
               
                if (comboBox1.SelectedIndex > -1)
                {
                    if (_current != null)
                    {
                        _current.XChanged -= OnCurrentXchanged; 
                    }
                    _current = _list[comboBox1.SelectedIndex];
                    _current.XChanged += OnCurrentXchanged;
                }
            }
    
            private void OnCurrentXchanged(object sender, EventArgs e)
            {
                Debug.WriteLine($"引發事件的物件是 {sender.GetType().Name }");
            }
    
            private void button1_Click(object sender, EventArgs e)
            {
                if (_current != null)
                {
                    _current.Exec1();
                }
    
                // 若要簡化,而且 C# 版本支援 ( >= 6.0) 的話可以寫成下方形式
               //  _current?.Exec1();
            }
    
            private void button2_Click(object sender, EventArgs e)
            {
                if (_current != null)
                {
                    _current.Exec2();
                }
                // 若要簡化,而且 C# 版本支援 ( >= 6.0) 的話可以寫成下方形式
                //  _current?.Exec2();
            }
    
            private void button3_Click(object sender, EventArgs e)
            {
                _current.X++;
            }
        }


    在現實生活中,你和誰在一起的確很重要,甚至能改變你的成長軌跡,決定你的人生成敗。 和什麼樣的人在一起,就會有什麼樣的人生。 和勤奮的人在一起,你不會懶惰; 和積極的人在一起,你不會消沈; 與智者同行,你會不同凡響; 與高人為伍,你能登上巔峰。 https://skilltree.my/

    • 已標示為解答 GaryChiang 2019年10月6日 下午 02:20
    2019年10月4日 下午 05:16
    版主
  • 1) 6~7個類別的物件不致於會造成記憶體的問題

    2) C#的delegate就是委派

    2019年10月5日 上午 12:34