20170717-20170723C#工作學習周總結

2017.07.17-2017.07.23

一、委託

委託實例化後可以與方法關聯,在調用委託的同時會調用與之關聯的方法。這使得我們可以把方法當作參數傳遞給其他方法。從運行方式來看,委託與C語言中的函數指針類似。

Q & A

Q:

C#中,直接用類名聲明一個變量和new一個對象有什麼區別?

A:

存儲方式不同,new在堆棧裏面,直接聲明的是局部變量了,運行的時候默認值爲null;

new的用完要delete,直接聲明函數執行完自動釋放了;

C#的new同時負責內存的分配以及把實例初始化成有效狀態;

Q:

多線程怎麼得到返回值

A:

線程就是用來處理併發的事情的,而你所說的線程的返回值,實際上,你的思想仍然停留在函數調用的模式上(把線程看成了函數)
線程的返回值問題,最理想的辦法就是線程來通知調度線程,這個調度線程可以是主線程,也可以是一個專門的調度線程,每當任務線程完成了自己的工作,就通知調度線程來取結果,這樣才能夠發揮出多線程的優勢,而不是在那裏傻等。
如果你把主線程當做調度線程,而你的主線程存在消息循環,那麼,利用消息就是一個不錯的通知方式。
任務線程完成了工作之後,向主線程發消息,消息中可以把任務線程本身(線程類)發給主線程,然後在主線程中取出這個線程類,然後得到任務線程的處理結果。
而最爲主線程,只需要添加一個消息響應函數就可以了。

Q:

string[] a = new string[] { “1”, “2”, “3” };

我想給a追加一個 “4” 元素 怎麼寫呢?因爲別人的參數方法能接受 string[] 這個類型 因此不能用Array 求解決!

A:

string[] a = new string[] { “1”, “2”, “3” };
List b = a.ToList();
b.Add(“4”);
a = b.ToArray();

一般習慣先轉List,處理完了再丟給數組。

二、一個簡單的跨線程更新UI(進度條)的程序

//TestClass類,可以用來,線程函數在其中實現
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace _20170720
{
    class TestClass
    {
        public delegate void testDelegate(long i);

        public testDelegate mainThread;
        public void TestFunction()
        {
            long i = 0;
            while (true)
            {
                i++;
                if (mainThread !=null)
                {
                    mainThread(i);
                }
                Thread.Sleep(100);
            }
        }
    }
}
//Program類,用來實現窗體及更新UI
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Forms;

namespace _20170720
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            //創建TestClass類的對象
            TestClass testclass = new TestClass();

            testclass.mainThread = new TestClass.testDelegate(refreshLabMessage1);
            testclass.mainThread += new TestClass.testDelegate(refreshLabMessage2);
            testclass.mainThread = new TestClass.testDelegate(refreshProgressBar);

            Thread testClassThread = new Thread(new ThreadStart(testclass.TestFunction));

            testClassThread.Start();
        }

        private void refreshLabMessage1(long i)
        {
            if (this.label1.InvokeRequired)
            {
                if(label1.Disposing||label1.IsDisposed)
                {
                    return;
                }

                TestClass testclass = new TestClass();
                testclass.mainThread = new TestClass.testDelegate(refreshLabMessage1);

                this.Invoke(testclass.mainThread, new object[] { i });
            }
            else
            {
                label1.Text = i.ToString();
            }
        }

        private void refreshLabMessage2(long i)
        {
            if (this.label1.InvokeRequired)
            {
                if (label1.Disposing || label1.IsDisposed)
                {
                    return;
                }

                TestClass testclass = new TestClass();
                testclass.mainThread = new TestClass.testDelegate(refreshLabMessage2);

                this.Invoke(testclass.mainThread, new object[] { i });
            }
            else
            {
                label1.Text = i.ToString();
            }
        }

        private void refreshProgressBar(long i)
        {
            if (progressBar1.InvokeRequired)
            {
                if(progressBar1.Disposing||progressBar1.IsDisposed)
                {
                    return;
                }

                TestClass testclass = new TestClass();
                testclass.mainThread = new TestClass.testDelegate(refreshProgressBar);
                this.Invoke(testclass.mainThread, new object[] { i });
            }

            else
            {
                progressBar1.Value = (int)i;
            }
        }
    }
}

三、一個對象數組排序的實例

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace dele
{
    class Program
    {
        static void Main(string[] args)
        {
            StudentInformationClass[] studentsInfo;

            Student[] students = new Student[]{
                new Student(){Age = 10,Name="張三",Score=70},
                new Student(){Age = 12,Name="李四",Score=97},
                new Student(){Age = 11,Name="王五",Score=80},
                new Student(){Age = 9,Name="趙六",Score=66},
                new Student(){Age = 12,Name="司馬",Score=90},
            };

            Console.WriteLine("--------------默認排序輸出--------");
            Array.Sort(students);
            Array.ForEach<Student>(students, (s) => Console.WriteLine(string.Format("{0}{1,2}歲了,他的分數是{2,3}", s.Name, s.Age, s.Score)));

            Console.Read();
        }
    }

    public class Student:IComparable
    {
        public int Age { get; set; }

        public string Name { get; set; }

        public int Score { get; set; }

        /// <summary>
        /// 實現IComparable接口,用Age做比較
        /// </summary>
        /// <param name="obj">比較對象</param>
        /// <returns>比較結果</returns>
        public int CompareTo(object obj)
        {
            if (obj is Student)
            {
                return Age.CompareTo(((Student)obj).Age);
            }

            return 1;
        }
    }
}

關於構造函數

類當中會有一個默認的無參數的構造函數,當寫了一個新的構造函數之後不管是有參的還是無參的,默認的構造函數都會被幹掉,這個時候要想用類原來默認的構造函數,就需要加:this()

WIMP

指:windows,icon,menus&pointer,是圖形界面電腦所採用的界面典範。

  • A window runs a self-contained program, isolated from other programs that (if in a multi-program operating system) run at the same time in other windows.
  • An icon acts as a shortcut to an action the computer performs (e.g., execute a program or task).
  • A menu is a text or icon-based selection system that selects and executes programs or tasks.
  • The pointer is an onscreen symbol that represents movement of a physical device that the user controls to select icons, data elements, etc.

window和control爲同一個父類。

事件和消息機制的理解

一個/條消息可以理解爲是一個數據結構,包含以下幾個基本部分:

  1. 消息源 :就是消息的來源,發出這個消息的對象
  2. 消息名 :就是消息的唯一標示
  3. 消息數據:消息發出後附帶的數據,有可能數據是空

消息從種類上又可以分爲2種:

  1. 系統消息 :由操作系統或deviceone系統發送出來的消息,消息的名稱是固定的。
  2. 自定義消息:由開發者自己定義,自己發送出來的消息,消息的名字是隨意的,可以任意定義。

發佈/訂閱模式是最常用的設計模式之一,是消息機制的核心,其特點就是降低耦合度,讓二個獨立的對象不互相依賴。

img

  1. 消費者和出版社互相不認識,消費者不需要了解他想要的雜誌是具體哪家出版社出的;出版社也不需要了解具體是哪個人定了他們出版社發行的書。
  2. 消費者和出版社必須都認識郵局。
  3. 消費者需要告訴郵局消費者的名字地址以及想要訂閱的雜誌名字
  4. 可以多個消費者訂閱同一本雜誌
  5. 郵局拿到雜誌後,會一一通知消費者,通知的時候同時把雜誌送到消費者手裏。

img

和上面的實際例子描述一一對應:

  1. 系統/開發者和函數對象互相不依賴,系統/開發者只管觸發一個消息,並不關心誰去接受
  2. 系統/開發者和函數對象必須能獲取到消息源對象
  3. 函數對象訂閱消息的時候需要標示消息的名稱和函數對象的引用
  4. 可以多個函數對象訂閱同一個消息源同一名字的消息
  5. 消息源觸發消息會一一通知所有訂閱者,並把data數據傳遞到回調函數對象

事件:只能由用戶通過外設的輸入產生。

消息:(產生消息的來源有三個) (1) 由操作系統產生。 (2) 由用戶觸發的事件轉換而來。 (3) 由另一個消息產生。

在C#中定義一個事件,首先要創造一個委託,用委託來定義一個你想使用的事件的標籤,然後才能使用event關鍵字,在這個委託的基礎上定義一個事件,然後把觸發事件的源和事件處理機制關聯起來。

繼承

繼承、封裝和多態是面向對象編程的重要特性。其成員被繼承的類叫基類也稱父類,繼承其成員的類叫派生類

也稱子類。

派生類隱式獲得基類的除構造函數和析構函數以外的所有成員。

派生類只能有一個直接基類,所以C#並不支持多重繼承,但一個基類可以有多個直接派生類。
繼承是可以傳遞的。

即:

如果 ClassB 派生出 ClassC,ClassA 派生出 ClassB,則 ClassC 會繼承 ClassB 和 ClassA 中聲明的成員。

析構函數與構造函數的區別

析構函數用於釋放被佔用的系統資源。

  1. 構造函數和析構函數是在類中說明的兩種特殊的成員函數。
  2. 構造函數是在創建對象時,使用給定的值將對象初始化。
  3. 析構函數用於釋放一個對象。在對象刪除前,使用析構函數做一些清理工作,它與構造函數的功能正好相反。

自定義控件

在編程的過程中,當現有C#的控件滿足不了我們的業務需求時,這就需要自己開發組件來達到我們的要求,即我們通常所說的自定義組件,在C#中,自定義組件分爲三種:

  1. 複合控件(Composite Controls):將現有的各種控件組合起來,形成一個新的控件,來滿足用戶的需求。
  2. 擴展控件(Extended Controls):就是在現有的控件基礎上,派生出一個新的控件,增加新的功能,或者修改原有功能,來滿足用戶需求。
  3. 自定義控件(Custom Controls):就是直接從System.Windows.Forms.Control類派生,也就是說完全由自己來設計、實現一個全新的控件。

​ 第一種方法比較簡單,直接拼湊即可,但是功能上 比不上第二、三種;第二種是比較常見的方法,對現有控件的屬性、方法等進行擴展,功能上基本能滿足一般的需求。第三種實現的功能更強大,也更靈活,從Control類繼承,控件的屬性、方法、事件等全部由自己編碼實現,這要求編寫者擁有一定的C#編程經驗和GDI/GDI+技能。

比如,可以用複合控件(用戶控件)來實現文件的打開並顯示路徑。即將textbox和button結合起來,將接口留給屬性,用get/set方法實現。

關於內核

內核對象即CPU特權指令,內核即指執行特權指令的那部分代碼。與Handle交互的時候要用到內核對象,句柄會泄露,打開就要負責關閉。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章