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爲同一個父類。
事件和消息機制的理解
一個/條消息可以理解爲是一個數據結構,包含以下幾個基本部分:
- 消息源 :就是消息的來源,發出這個消息的對象
- 消息名 :就是消息的唯一標示
- 消息數據:消息發出後附帶的數據,有可能數據是空
消息從種類上又可以分爲2種:
- 系統消息 :由操作系統或deviceone系統發送出來的消息,消息的名稱是固定的。
- 自定義消息:由開發者自己定義,自己發送出來的消息,消息的名字是隨意的,可以任意定義。
發佈/訂閱模式是最常用的設計模式之一,是消息機制的核心,其特點就是降低耦合度,讓二個獨立的對象不互相依賴。
- 消費者和出版社互相不認識,消費者不需要了解他想要的雜誌是具體哪家出版社出的;出版社也不需要了解具體是哪個人定了他們出版社發行的書。
- 消費者和出版社必須都認識郵局。
- 消費者需要告訴郵局消費者的名字地址以及想要訂閱的雜誌名字
- 可以多個消費者訂閱同一本雜誌
- 郵局拿到雜誌後,會一一通知消費者,通知的時候同時把雜誌送到消費者手裏。
和上面的實際例子描述一一對應:
- 系統/開發者和函數對象互相不依賴,系統/開發者只管觸發一個消息,並不關心誰去接受
- 系統/開發者和函數對象必須能獲取到消息源對象
- 函數對象訂閱消息的時候需要標示消息的名稱和函數對象的引用
- 可以多個函數對象訂閱同一個消息源同一名字的消息
- 消息源觸發消息會一一通知所有訂閱者,並把data數據傳遞到回調函數對象
事件:只能由用戶通過外設的輸入產生。
消息:(產生消息的來源有三個) (1) 由操作系統產生。 (2) 由用戶觸發的事件轉換而來。 (3) 由另一個消息產生。
在C#中定義一個事件,首先要創造一個委託,用委託來定義一個你想使用的事件的標籤,然後才能使用event關鍵字,在這個委託的基礎上定義一個事件,然後把觸發事件的源和事件處理機制關聯起來。
繼承
繼承、封裝和多態是面向對象編程的重要特性。其成員被繼承的類叫基類也稱父類,繼承其成員的類叫派生類
也稱子類。
派生類隱式獲得基類的除構造函數和析構函數以外的所有成員。
派生類只能有一個直接基類,所以C#並不支持多重繼承,但一個基類可以有多個直接派生類。
繼承是可以傳遞的。
即:
如果 ClassB 派生出 ClassC,ClassA 派生出 ClassB,則 ClassC 會繼承 ClassB 和 ClassA 中聲明的成員。
析構函數與構造函數的區別
析構函數用於釋放被佔用的系統資源。
- 構造函數和析構函數是在類中說明的兩種特殊的成員函數。
- 構造函數是在創建對象時,使用給定的值將對象初始化。
- 析構函數用於釋放一個對象。在對象刪除前,使用析構函數做一些清理工作,它與構造函數的功能正好相反。
自定義控件
在編程的過程中,當現有C#的控件滿足不了我們的業務需求時,這就需要自己開發組件來達到我們的要求,即我們通常所說的自定義組件,在C#中,自定義組件分爲三種:
- 複合控件(Composite Controls):將現有的各種控件組合起來,形成一個新的控件,來滿足用戶的需求。
- 擴展控件(Extended Controls):就是在現有的控件基礎上,派生出一個新的控件,增加新的功能,或者修改原有功能,來滿足用戶需求。
- 自定義控件(Custom Controls):就是直接從System.Windows.Forms.Control類派生,也就是說完全由自己來設計、實現一個全新的控件。
第一種方法比較簡單,直接拼湊即可,但是功能上 比不上第二、三種;第二種是比較常見的方法,對現有控件的屬性、方法等進行擴展,功能上基本能滿足一般的需求。第三種實現的功能更強大,也更靈活,從Control類繼承,控件的屬性、方法、事件等全部由自己編碼實現,這要求編寫者擁有一定的C#編程經驗和GDI/GDI+技能。
比如,可以用複合控件(用戶控件)來實現文件的打開並顯示路徑。即將textbox和button結合起來,將接口留給屬性,用get/set方法實現。
關於內核
內核對象即CPU特權指令,內核即指執行特權指令的那部分代碼。與Handle交互的時候要用到內核對象,句柄會泄露,打開就要負責關閉。