會發生這個 error 的原因是: The code is trying to access a member of a reference type variable that is set to null.
當使用automatic properties 的時候,如果沒有初始化 value type 的 property 會是 0, reference type 則會是 null。因此在建構子當中要針對 properties 做初始化的動作 ( "new" )
參考: http://blogs.msdn.com/csharpfaq/archive/2004/05/06/127647.aspx
...
1/12/2010
1/04/2010
[C# 筆記] Collections and Generics 集合和泛型
- Collections 解決 System.Array 只能裝載同一型別之物件和固定長度的容量之限制。Generics 提供更高的 type safety 和 performance。
- System.Collections 這個 namespace 實現了許多 interfaces 像是: ICollection, IComparer, IDictionary, IDictionaryEnumerator, IEnumerable, IEnumerator, IHashCodeProvider, IList
- The Role of ICollection
- ICollection 是最主要的 interface,他允許你 (a) 取得 container 內物件的數量 (b) the thread safety of the container (c) the ability to copy the contents into a System.Array type
- public interface ICollection : IEnumerable
{
int Count { get; }
bool IsSynchronized { get; }
object SyncRoot { get; }
void CopyTo(Array array, int index);
}
- The Role of IDictionary
- A dictionary is simply a collection that maintains a set of name/value pairs
- public interface IDictionary : ICollection, IEnumerable
{
bool IsFixedSize { get; }
bool IsReadOnly { get; }
// Type indexer; see Chapter 12 for full details.
object this[object key] { get; set; }
ICollection Keys { get; }
ICollection Values { get; }
void Add(object key, object value);
void Clear();
bool Contains(object key);
IDictionaryEnumerator GetEnumerator();
void Remove(object key);
}
- The Role of IDictionaryEnumerator
- IDictionaryEnumerator is simply a strongly typed enumerator, given that it extends IEnumerator by adding the following functionality:
public interface IDictionaryEnumerator : IEnumerator
{
DictionaryEntry Entry { get; }
object Key { get; }
object Value { get; }
}
- The Role of IList
- provides the ability to insert, remove, and index items into (or out of) a container
- public interface IList : ICollection, IEnumerable
{
bool IsFixedSize { get; }
bool IsReadOnly { get; }
object this[ int index ] { get; set; }
int Add(object value);
void Clear();
bool Contains(object value);
int IndexOf(object value);
void Insert(int index, object value);
void Remove(object value);
void RemoveAt(int index);
}
- The Class Types of System.Collections
Labels:
C#,
collections,
generics,
note
12/23/2009
[C# 筆記] Interfaces 介面
- 自訂型別可以實現內建 interface 來擴充自己的功能。
- interface 只是一群 abstract members 的集合。interface 表達一種 behavior 可以讓 class 或 structure 選擇去 implement 這樣的 behavior。
- interface 當中只有 property 和 method 成員,而且所有成員都是 abstract。
- Interface Types 和 Abstract Base Class 的差異
- Abstrace Base Class 可以定義 constructor, field 和 nonabstract members;但是 Interface 只能包含 abstract members。
- 由 abstract parent class 所建構出的多型有一個主要的限制,就是只有 derived types 支援 abstract parent 定義的成員。因此無法要求在不同繼承階層下的 types 支援相同的多型介面。相反的,一旦定義了 interface,他可以被任何型別 implement,再任意的繼承階層之中,甚至任意的 namespace 或 assembly。
- 假如有一個 method 叫做 CloneMe() 並且 take 一個 ICloneable interface 為輸入參數,我們就可以將任何實做了 ICloneable interface 的物件 (即使這些物件不屬於同一個繼承階層) 傳入 CloneMe() 方法當中。換句話說,透過 interface 可以讓不屬於同一個 inherence hierachy 的 class 也能實現多型。
- abstract base class 另外一個限制是,所有 derived type 針對每一個 abstract member 都要提供具體的 implement,即使有時候 derived type 去實現那個 member 沒有甚麼意義的時候,也是得照做。interface 則可以避免這個缺點,它就像是一個隨插即用的 usb,需要他的時候在 implement 他即可。
- Defining Custom Interfaces
- 所有 interface members 都是隱含宣告為 public 和 abstract。
- Interfaces 只是單純的 protocol 不能包含實做。
- Implementing an Interface
- 如果一個類別要繼承又要 plug-in interface 的話,在 : 後面要先寫繼承,然後再寫 interface。
- 一旦 plug-in 了該 interface,就必須實現所有 interface 當中的 member。
- Invoking Interface Members at the Object Level
- 一旦你的 class plug-in 了某個 interface,接下來該怎麼使用 interface 提供的 functionality 呢? 直接的做法是,宣告一個物件,然後呼叫 class 當中實現完成的 interface function。但是除非你就是這個 class 的實作者,不然經常妳是不知道這個 class 是否 support 某個 interface,於是就產生了這個問題: How can we dynamically determine the set of interfaces supported by a type?
- Interfaces As Parameters
- Interfaces As Return Values

- Arrays of Interface Types
- Resolving Name Clashes via Explicit Interface Implementation
- 由於 class 並沒有限制可以 plug 上多少的 interface,當一個 class plug 上多個 interface的時候,interfaces 當中的 member 可能會有重覆命名的情況發生 (Name Clashes)。
- 若 A class plug-in 了 B 和 C interfaces,B 和 C 都有 D method,如果 A class 直接實現 D 方法,並無法鑑別出 B 和 C 有何差異。因此需要 explicit interface implementation: 就是在方法的前面明確的指出是哪一個 interface ( e.g. void B.D (arg) {...} )。
- 並且注意,在使用 explicit interface implementation 時前方不需要加 access modifier,其將自動為 private。因此,這些成員將無法透過 object level 取得,也無法透過 . 來看到該成員。
- 因此你必須透過 explicit casting 來取得該成員的功能。例如: B a_b = (B)A; a_b.D,先將 A 轉成 B interface a_b,再從 a_b 取出 D method。
- 凡透過 explicit interface implementation 的 member 都將被設成 private,某種程度來說是一種封裝,而想要更進一步利用 interface 功能者,則要自行用 explicit casting 提取出來使用。
- Interface Hierarchies
- when an interface extends an existing interface, it inherits the abstract members defined by the parent type(s)
- Interface hierarchies can be useful when you wish to extend the functionality of an existing interface without breaking existing code bases
- we are able to invoke each method at the object level (as they are all public) as well as extract out a reference to each supported interface explicitly via casting
- Multiple inheritance for interface types is a-okay
- Interfaces can be extremely useful when
- You have a single hierarchy where only a subset of the derived types support a common behavior
- You need to model a common behavior that is found across multiple hierarchies with no common parent class beyond System.Object
- Building Enumerable Types
- C# 中的 foreach 可以 loop 陣列當中的每一個 element,其實真正的關鍵是任何型別只要支援一個方法 GetEnumerator 都可以使用 foreach。
- 假如你自行創建了一個類別,並宣告了一個陣列當中存放該類別創造出的物件,那麼並無法使用 foreach 去 loop,compiler 會告訴你該類別並沒有實現 GetEnumerator 這個方法。
- GetEnumerator 這個方法存在於 IEnumerable interface 當中,此介面潛藏於 System.Collections 當中,支援此 interface 的型別代表可以 expose sub items to caller。
- 要使自定的物件可以使用 foreach,一個方式就是精確的在該類別當中清楚的定義 IEnumerable 當中每一個 member,或者比較簡單的方式,在類別當中宣告一個 GetEnumerator 方法,在方法的定義中使用 Array 本身的 GetEnumerator 方法當作 return 值。
- 由於 GetEnumerator 方法的返回值是一個 IEnumerable 介面,如上述所做 object user 可以呼叫 GetEnumerator 方法取得 IEnumerable 介面進而使用該介面當中的其他方法取得陣列中的物件,若要避免 object user 取得 IEnumerable 介面可以使用 explicit interface implementation。
- 另外一種方法就是利用 iterator,使用這種方式一樣要在類別當中宣告一個 GetEnumerator 方法並且返回值也是 IEnumerable 介面,不同的是該類別不需要 plug-in 任何 interface。


- 也可以不使用 internal 的 foreach (如上圖),而使用 yield return 的好處是,可以將 class 當中的內部資料丟出去給 foreach 使用。
- yield 這個 keyword 不一定要在GetEnumerator 中使用,可以用在任何 method 當中,這些方法技術上的名稱是 named iterators,建構這種方法必須清楚他的回傳值是 IEnumerable interface。
- 這個方法的好處是可以讓一個單一的 container 定義多種方式去拿到他的回傳值,例如 順排 或 逆排。


- Building Cloneable Objects (ICloneable)
- public interface ICloneable
{
object Clone();
} - value type 和 reference type 的不同就是當你 assign value type 的變數給另一個變數的時候是複製一份,而 reference type 的話則是指向同一個物件的記憶體位置。所以,當你想要讓自定的 class (reference type) 可以擁有像 value type 那樣的 "複製一份" 的功能,就需要實做 ICloneable interface,這個 interface 定義了一個方法 Clone()
- 實做 Clone() 方法依 class 的定義各有不同,不過基本上就是將成員變數的值複製到一個新的物件,再將這個物件 return 給 user。注意: Clone() 方法 return 值是一般的物件型別,因此要 assign 的時候要用 explicit cast ! ( e.g. Point p4 = (Point)p3.Clone(); )
- 當類別中並沒有任何 reference type 的成員,可以用更簡易的方法實做 Clone() 方法,
public object Clone()
{
// Copy each field of the Point member by member.
return this.MemberwiseClone();
}
- 但是,當類別當中有 reference type 的成員時,使用 MemberwiseClone() 會導致 shallow copy,即該 reference type 成員並沒有被複製一份,導致兩個不同物件之間更動一個物件的該 reference type 成員,另一物件的該 reference type 成員也會跟著更動。
- 假若你希望達到 deep copy 的話,則必須在 Clone() 當中執行完 MemberwiseClone() 之後,針對 reference type 的成員,再另行宣告一個新的物件,將當前的值 copy 進去,然後再刷新 MemberwiseClone() return 出來的物件的該成員。
public object Clone()
{
// First get a shallow copy.
Point newPoint = (Point)this.MemberwiseClone();
// Then fill in the gaps.
PointDescription currentDesc = new PointDescription();
currentDesc.petName = this.desc.petName;
newPoint.desc = currentDesc;
return newPoint;
}
- Building Comparable Objects (IComparable)
- 此介面允許物件根據特定的 key 來排序。
public interface IComparable
{
int CompareTo(object o);
}
- 假設你自定了一個類別 Car,並且宣告了一個陣列 CarArray 當中裝有該類別的物件,這時你呼叫 CarArray.Sort() 時會跳出 exception 告訴你需要實現 IComparable 介面。
// The iteration of the Car can be ordered
// based on the CarID.
public class Car : IComparable
{
...
// IComparable implementation.
int IComparable.CompareTo(object obj)
{
Car temp = (Car)obj;
if(this.carID > temp.carID)
return 1; (come after, 越大的排越後面)
if(this.carID < temp.carID)
return -1; (come before, 越小的排越前面)
else
return 0;
}
}
- 若你希望按照類別中的某個成員變數來排序,而該成員變數又是屬於 intrinsic type 的話,可以直接套用該變數的 CompareTo() 方法。
int IComparable.CompareTo(object obj)
{
Car temp = (Car)obj;
return this.carID.CompareTo(temp.carID);
}
- Specifying Multiple Sort Orders (IComparer),當你想要根據不只一個成員來做排序的話,那麼就要利用到另外一個 interface "IComparer", 該介面定義如下:
// A generic way to compare two objects.
interface IComparer
{
int Compare(object o1, object o2);
}
- IComparer 介面並非在你想要排序的型別中實現,通常是在 helper class 當中實現這個介面。而這個 helper class 剛好可以當作 System.Array 當中 Sort() 方法的一個輸入參數:
// This helper class is used to sort an array of Cars by pet name.
using System.Collections;
public class PetNameComparer : IComparer
{
// Test the pet name of each object.
int IComparer.Compare(object o1, object o2)
{
Car t1 = (Car)o1;
Car t2 = (Car)o2;
return String.Compare(t1.PetName, t2.PetName);
}
}
static void Main(string[] args)
- {
- ...
- // Now sort by pet name.
- Array.Sort(myAutos, new PetNameComparer());
}
- Custom Properties,Custom Sort Types 也可以將 helper class 寫進該類別的 properties 當中,這樣就可以直接在 Sort() 的參數直接取 property,更為直覺。
Labels:
C#,
interfaces,
note
12/21/2009
[FQL] Stream filter
Ref: http://wiki.developers.facebook.com/index.php/Stream_filter_(FQL)
- uid
- uid in the where clause must be the session user
- filter_key
- name
- rank
- icon_url
- 目前拿來分類 status, link, photo 的賤招
- is_visible
- 判斷這個分類是否隱藏於 "More" 之中
- type
- The type of filter. One of application, newsfeed, friendlist, network, or publicprofile.
- value
[C# 筆記] Polymorphic 多型
- 當 base class 定義了一個 public method,所有的子類別分支(相關型別) 對於這個方法的反應都是一樣的。如何使相關型別對於同一個 request 做出不同的 respond 就是多形所要探討的。
- virtual and override Keywords
- 若一 base class 希望當中定義的 method 可以(may be)被覆寫,那麼就要使用 "virtual";若一子類別要覆寫 base class 的 virtual method 的話,則要加上 "override"。
- 在 overriden method 當中不一定要全部重新定義,可以透過 "base" 來存取原 base class 的功能。
- Sealing Virtual Members
- 有時候只是想把 class 當中的某個 virtual method 給 seal 起來,讓子類別無法進行覆寫,而非對整個 class seal。這時候可以針對 virtual method 下 "sealed" Keyword
- Abstract Classes
- base class 通常定義一般性的物件元素,創建 base class 的物件通常不具有太大的意義,因此可以透過 "abstract" 來避免針對 base class 進行物件的創建。
- 在 abstract class 當中,可以定義 abstract member,這種 member 可以完全不定義其 default implementation (不同於 viutual)。因此你強迫了每一個繼承此類別的子類別自行定義該方法之實做。
- Member Shadowing
- 假若子類別定義了一個和父類別一模一樣的成員,那麼子類別的版本會覆蓋父類別的版本。
- 當你從外部取得一個類別,而要將此外部類別融入你的 base class 的時候,就可能會發生 member shadowing 的情形。這時候會得到一個 warning,有兩種解決方式。一、返回 base class 將被 shadow 的 method 加上 "virtual"。二、針對該子類別的 shadowing method 加上 "new",意味著覆蓋所有在此之前的版本。
- Base Class/Derived Class Casting Rules
- 用 base class type 宣告的陣列當中可以放其子類別創建的物件(implicit cast)。it is always safe to store a derived type within a base class reference (e.g. baseclass A = new derived ();) 。
- 這麼做的好處是當你定義一個方法的輸入參數為 base class reference,那麼你就可以傳遞所有 derived class 的物件到這個方法當中。
- 除了 implicit cast 還可以直接用 explicit cast 硬轉,但是不是每種狀況都可以硬轉,C# 提供 "as" Keyword 讓你檢查兩個物件的 compatability。
- Hexagon hex = (Hexagon)frank;
Hexagon hex2 = frank as Hexagon;
if (hex2 == null)
Console.WriteLine("Sorry, frank is not a Hexagon...");
- 第二點當中的方法要怎麼知道丟進來的物件是哪一個 derived type 來做相對應的處理(知道是哪一個derived type 之後再用 explicit cast) 呢? C# 提供 "is" Keyword 和 "as" 相似,只是如果兩個物件 incompatable 的話 "as" 會返回 null, "is" 會返回 false。
Labels:
C#,
note,
polymorphic
12/20/2009
[C# 筆記] Inheritance 繼承
- code reuse 有兩個面向: 一種是 is-a ( classical inheritance) 關係、一種是 has-a (containment/delegation) 關係。
- 所謂 has-a 關係允許一個類別定義一個其他類別的成員變數,並且把該成員變數的 functionality 間接的 expose 給該類別使用者。這也達到封裝 (data hiding) 的目的,因為如此一來該物件使用者並不知道該類別中還包含了另一個類別成員變數。
- 子類別若定義新的成員,該成員並不能存取父類別的 private member。
- C# 當中沒有多重繼承,一個類別只能繼承自單一父類別。但是 interface 則可以 derive frome multiple interfaces。
- sealed Keyword
- 使該 class 無法被繼承
- C# structures 隱含預設為 sealed 即無法被繼承
- base Keyword
- 子類別建構子當中的參數,如果是要拿來初始化父類別的欄位資料的話,需要使用 "base" 來增加初始化的效率。
- public Manager(string fullName, int age, int empID, float currPay, string ssn, int numbOfOpts) : base(fullName, age, empID, currPay, ssn) 例如:前五個參數主要拿來初始化繼承而來的 field data,因此用 "base" 明確指定對應到哪個欄位
- 使用 "protected" 的好處是: 子類別要存取父類別當中的 protected 成員不再需要透過 public 的 properties,而可以直接存取。當然這會造成一些封裝的危險,即可以透過子類別改變父類別的 internal data。Although protected field data can break encapsulation,it is quite safe (and useful) to define protected methods.When building class hierarchies,it is very common to define a set of methods that are only for use by derived types
- protected 成員在非家族類別的眼中即為 private。
- 在繼承分支到最後,一些子類別在分支下去也許沒有太大的意義,這時候可以利用 "sealed" Keyword 避免該類別再一步被 extend,也就是無法被繼承。
- 要描述 has-a 的關係很簡單,只要在一個類別 A 當中宣告另一個類別的物件 B,即能表達 A contains B 的概念。所謂 Delegation 指的則是在 A 中創建一個方法,讓使用者可以透過者個透露在外頭的 A 的方法,而完成 B 所能達到的功能性。
- Nested Type (巢狀型別)
- 巢狀型別允許對於 inner type 得到完全的 accessru,即使被宣告成 private。
- 因為 inner type 屬於 outer class 的一個成員,因此他可以存取 outer class 的 private 成員。
- inner type 經常扮演 outer class 的 helper,而並非為外部所用。
Labels:
C#,
inheritance,
note
Subscribe to:
Posts (Atom)


