C#編程筆記一
---恢復內容開始---
編程筆記
override與new實現的版本控制
// versioning.cs // CS0114 expected public class MyBase { public virtual string Meth1() { return "MyBase-Meth1"; } public virtual string Meth2() { return "MyBase-Meth2"; } public virtual string Meth3() { return "MyBase-Meth3"; } } class MyDerived : MyBase { // Overrides the virtual method Meth1 using the override keyword: public override string Meth1() { return "MyDerived-Meth1"; } // Explicitly hide the virtual method Meth2 using the new // keyword: public new string Meth2() { return"MyDerived-Meth2"; } // Because no keyword is specified in the following declaration // a warning will be issued to alert the programmer that // the method hides the inherited member MyBase.Meth3(): public string Meth3() { return "MyDerived-Meth3"; } public static void Main() { MyDerived mD= new MyDerived(); MyBase mB = (MyBase) mD; System.Console.WriteLine(mB.Meth1()); System.Console.WriteLine(mB.Meth2()); System.Console.WriteLine(mB.Meth3()); } }
問題:將借口的類型作為返回對象是什麽意思。。。
問題在下一個章節的解答中。
就是叠代器的實現,用來和foreach來匹配
另外Unity裏的協程用到的也是叠代器的方法。
上個示例代碼
using System; using System.Collections; using System.Collections.Generic; using UnityEngine; class testClass : MonoBehaviour { void Start() { print("?"); TestEnum _t = new TestEnum(10); foreach (string item in _t) { print(item); } } } class TestEnum : IEnumerable { /// <summary> /// 生成n組n位隨機數序列 /// </summary> public TestEnum(int num) { _Id = new string[num]; for(int i = 0; i < num; i++) { _Id[i] = UnityEngine.Random.Range(0, 10000f).ToString(); } } string[] _Id; public IEnumerator GetEnumerator() { return new TestEnumtor(this); } class TestEnumtor : IEnumerator { private TestEnum testEnum; private int index = 0; public TestEnumtor(TestEnum testEnum) { this.testEnum = testEnum; } public object Current { get { return testEnum._Id[index]; } } public bool MoveNext() { if (index < testEnum._Id.Length-1) { index++; return true; } else { return false; } } public void Reset() { index = -1; } } }
關於結構和類:
起碼的一點,結構是值類型,類對象是引用類型。
同樣的,傳參時結構是按值傳遞,而類是按引用傳遞。
結構不能定義默認構造函數
使用 New 運算符創建結構對象時,將創建該結構對象,並且調用適當的構造函數。與類不同的是,結構的實例化可以不使用 New 運算符。如果不使用“新建”(new),那麽在初始化所有字段之前,字段將保持未賦值狀態,且對象不可用。
對於結構,不像類那樣存在繼承。一個結構不能從另一個結構或類繼承,而且不能作為一個類的基。但是,結構從基類對象繼承。結構可實現接口,而且實現方式與類實現接口的方式完全相同。以下是結構實現接口的代碼片段:
索引器的用法
就是能用索引器的方式來返回類裏的屬性,具體在VS裏找到indexer這個提示符就可以補全出這個結構來了,不做贅述.
但是需要註意一點,這個方法最好是get和set屬性都使用。一旦只使用set屬性,還不如直接用方法來實現,不要用索引器
類型轉換
隱式轉換implicit和顯式轉換explicit,也比較好理解。語法上也是結合了運算符重載。
定義了同類型的顯示轉換/隱式轉換就不需要定義另外一種了。
另外記住要聲明為static。
直接上個例子就行了
static public implicit operator int(TestEnum te) { Debug.Log("隱式轉換"); return te.length; } static public explicit operator int(TestEnum te) { Debug.Log("顯示轉換"); return te.length; }
(當然,兩個都寫在這裏是錯誤的)
隱式轉換是非常強力的編程工具,但是也可能帶來比較難維護的問題吧感覺。 重載運算符 基本和C++的差不多,但是C#的相對來說靈活一點。比如說,+運算符的第一個參數不一定需要是這個類的對象。不像C++裏面那樣對於二目運算符裏的左操作數對類型有要求。(比如<<這個運算符,重載IO流還需要聲明是friend) 上個例static public TestEnum operator +(int t1,TestEnum t2) { return t1+t2.length; }
(這個功能太強了)
當然,這麽寫的前提是,我定義了從int到TestEnum的隱式轉換
static public implicit operator TestEnum(int i) { return new TestEnum(i); }
(所以說隱式轉換功力很強勁啊…………)
委托和事件:
之前在《u3d腳本編程》這本書裏了解了一些有關知識,再看一遍MSDN上的也就相當於復習。
摘一些MSDN上的TIPs好了,也不能說現在完全理解吧,慢慢理解還是可以的。先碼
委托在以下情況下很有用:
- 調用單個方法。
- 一個類可能希望有方法規範的多個實現。
- 希望允許使用靜態方法實現規範。
- 希望類似事件的設計模式。
- 調用方不需要知道或獲得在其上定義方法的對象。
- 實現的提供程序希望只對少數選擇組件“分發”規範實現。
- 需要方便的組合。
接口在以下情況下很有用:
- 規範定義將調用的一組相關方法。
- 類通常只實現規範一次。
- 接口的調用方希望轉換為接口類型或從接口類型轉換,以獲得其他接口或類。
事件按照.NET的標準來的話,就是最好使用EventHandler,或者它的泛型版本(泛型版本是改變了EventArg的類型,一般是繼承了EventArg的類(所以為什麽不也做一個Object的泛型安全類型版本呢…………))
下面是一個簡單的示例
class testClass : MonoBehaviour { void Start() { DataElement data1 = new DataElement("alex", 15); EventListener eva = new EventListener(data1); data1.Name = "tom"; data1.Age = 13; } } class DataElementMessage : EventArgs { public enum ChangeType { NAME, AGE, BOTH, NONE } ChangeType changeType; internal ChangeType ChangeType1 { get { return changeType; } set { changeType = value; } } public DataElementMessage(ChangeType changetypes) { this.ChangeType1 = changetypes; } } class DataElement { private string name; private int age; public string Name { get { return name; } set { name = value; Onchange(new DataElementMessage(DataElementMessage.ChangeType.NAME)); } } public int Age { get { return age; } set { age = value; Onchange(new DataElementMessage(DataElementMessage.ChangeType.AGE)); } } public event EventHandler<DataElementMessage> change; void Onchange(DataElementMessage e) { if (change != null) { change(this, e); } } public DataElement(string name, int age) { this.Name = name; this.Age = age; Onchange(new DataElementMessage(DataElementMessage.ChangeType.BOTH)); } } class EventListener { DataElement _eventsender; public EventListener(DataElement _e) { this._eventsender = _e; _e.change += ListChange; } public void ListChange(object sender, DataElementMessage message) { DataElement data = sender as DataElement; Debug.Log("changeType:" + message.ChangeType1.ToString() + " Age:" + data.Age + " Name:" + data.Name); } }
(當然這個實例沒有寫Detach,要寫也比較容易把,寫這個也就是熟悉一下基本框架。註意與MVC的聯合思考就好)
顯式實現接口:
怎麽顯式實現借口VS已經在自動補全裏告訴你了。這裏的關鍵是使用。
如果一個接口是顯式實現的,like this
interface testInterface { float Floating(); } class FloatInterface : testInterface { float testInterface.Floating() { return 2f; } }
那麽使用的時候,就必須用接口對象來實現,like this
FloatInterface I = new FloatInterface(); testInterface i = (testInterface)I; Debug.Log( i.Floating());
如果是非顯式實現的,那麽用FloatInterface的實例對象也可以進行接口調用,反之則不行。
那麽這個東西有什麽用呢?官方例子裏大概意思這麽寫了一個例子,我也簡化隨便寫了下
interface DoubleInterFace { float Floating(); } interface TrippleInterFace { float Floating(); } class FloatInterface : DoubleInterFace, TrippleInterFace { float DoubleInterFace.Floating() { return 2f; } float TrippleInterFace.Floating() { return 3f; } public float Floating() { return 1f; } } class testClass : MonoBehaviour { void Start() { FloatInterface _1f = new FloatInterface(); TrippleInterFace _3f = _1f; DoubleInterFace _2f = _1f; Debug.Log(_1f.Floating()); Debug.Log(_2f.Floating()); Debug.Log(_3f.Floating()); } }
輸出當然是1 2 3
編程筆記
C#編程筆記一