Fork me on GitHub

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?

      • 其中一個解法是 explicit cast,觀察 Circle class 是否 support IPointy interfaceCircle

        c = new Circle("Lisa");
        IPointy itfPt = null;
        try {
        itfPt = (IPointy)c;
        }
        catch (InvalidCastException e) {

        }

      • 第二個方法則是使用 "as" 或 "is","as" 如果不 support 會 return "null";"is" 如果不 support 會 return "false"。





  • Interfaces As Parameters

    • Interface 是 valid .NET types 因此也可當作 methods 的參數。只要任何 implement 了該 interface 的物件都可以傳遞進 methods 當中。

  • 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,更為直覺。

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。

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,而並非為外部所用。

    [C# 筆記] Encapsulation 封裝

    • Access Modifiers: 
      • 型別成員的隱含預設為 private, 型別的隱含預設為 internal 
      • Internal items are accessible only within the current assembly. Therefore, if you define a set of internal types within a .NET class library, other assemblies are not able to make use of them.
      • 希望類別創建的物件可以讓外部 assembly 使用就要把 class 加上 public,若希望類別當中的成員可以讓其他類別使用,也要將類別成員加上 public 。
      • 一般 class 不能加上 private,但是巢狀型別 (class 當中包含的別的型別的成員變數) 可以。
    • 利用 Type Properties 進行封裝
      • Properties make your types easier to manipulate, in that properties are able to respond to the intrinsic operators of C#。
      • A property really maps to a get_/set_ pair! 因此不能在類別當中在宣告 get_xxx, set_xxx 的方法
    • Properties 的  Visibility 
      • 在 get 或 set 之前加上 accessibility keyword (e.g. "protected")。
      • Read-Only / Write-Only 的 Property: 拿掉 get 或 set 其中一個即可。
      • The benefit of properties is that the users of your objects are able to manipulate the internal data point using a single named item
      • Constant Data
        • 利用 const 這個 keyword 定義在初始化之後其值不在改變的資料。
        • const field 隱含為 static,可以直接透過類別存取。
        • constant data 在 compile 的時候就必須知道該值,因此 const data 在宣告之後一定要給定初值。
      • Read-Only Fields (勿與 read-only property 混淆)
        • 剛好跟 const 不同,read-only field 可以不必在宣告之後馬上給定初值,因此可以透過建構子來指定初值 (讀取外部資料時有用)。
        • read-only field 並非隱含 static,如果設定成 class 層級,要加上 "static"。
      •  Partial Types
        • 允許你在多個 .cs 檔案中定義型別 (e.g. 可以將 properties 和 constructor 放在一個 .cs 檔,field data 和 type method 放在另外一個 .cs 檔)

        [C# 筆記] static Keyword

        • Invoked directly from the class level.
        • 沒有必要透過創建一個物件來 invoke 的成員,通常會宣告成 static member,,static member 經常出現在 utility class 當中。
        • 靜態成員只能操作其類別當中的靜態資料或靜態方法,不能操作非靜態成員。
        • 類別當中的靜態資料在記憶體中只佔一個位置,所有的物件都指向該資料
        • static methods can operate only on static data. However, a nonstatic method can
          make use of both static and nonstatic data... 非靜態方法可以 存取/修改 靜態和非靜態資料,可以用來實現單一個物件對靜態資料進行修改,進而同步到每一個物件當中。
        • 靜態建構子: 若類別建構子會重設靜態資料,那麼靜態資料在每一次的物件創見都會被重新設定一次。雖然說你可以在宣告靜態資料的時候就給定初值,但是有時候靜態資料的值是由資料庫或外部檔案所決定,因此有靜態建構子。
          • a static constructor is a special constructor that is an ideal place to initialize the values of static data when the value is not known at compile time
          • The runtime invokes the static constructor when it creates an instance of the class or before accessing the first static member invoked by the caller... 在物件創建之前或者直接存取類別成員
          • The static constructor executes before any instance-level constructors
        • 靜態類別: 當類別被宣告成靜態,便無法用 new 創建物件,也只能包含靜態欄位和靜態成員。

        12/16/2009

        FQL 整理

        Ref: http://wiki.developers.facebook.com/index.php/FQL_Tables

        [FQL] Friendlist

        Ref: http://wiki.developers.facebook.com/index.php/Friendlist_%28FQL%29

        • flid
          • 某類別朋友清單的 id。
          • 取得此欄位,再用他到 friendlist member Table 找出該清單所有朋友的 id。
        • name
          • 某類別朋友的名稱 (例: 國中同學)。
        • owner
          • 該朋友清單的擁有者 id。

        [FQL] Album

        Ref: http://wiki.developers.facebook.com/index.php/Album_%28FQL%29

        • aid
          • 每個相簿的唯一 id。
        • owner
          • 該相簿的擁有者 id。
        • cover_pid
          • 封面照片的 id。
        • name
          • 相簿名稱。
        • created
        • modified
        • description
          • 相簿描述。
        • location
        • size
          • 包含相片張數。
        • link
          • 相簿的網頁位址。
        • visible
          • 相簿的觀看權限。
        • modified_major
          •  相簿最近的更新時間 (例: 新增相片)
        • edit_link
        • type
          • profile, nobile, wall, normal
          • 也許可以拿來濾掉一些遊戲發布的照片。
        • object_id

        [FQL] Photo

        Ref: http://wiki.developers.facebook.com/index.php/Photo_%28FQL%29

        • pid
          • 照片的唯一 id。
        • aid
          • 該張照片屬於哪一本相簿,該相簿的唯一 id。
        • owner
          • 此照片的擁有者
        • src_small
        • src_small_height
        • src_small_width
        • src_big
        • src_big_height
        • src
        • src_height
        • src_width
        • link
          • 該照片的網頁位址。
        • caption
          • 該照片之描述。
        • created
        • modified
          • 該照片最近一次被修改的時間 (不包括 comment)
        • object_id
          • 如果利用某張照片的留言特性來篩選照片的話,會需要 object_id 這個欄位當作 WHERE 後方的條件欄位,但此欄位並非 indexable,因此要在前方塞入 pid 這個 indexable 的欄位。

        [FQL] Comment

        Ref: http://wiki.developers.facebook.com/index.php/Comment_%28FQL%29

        • xid
          • 傳說中每個 comment 串都會有一個 xid,但是始終這個欄位都是空的!
        • object_id
          • 每個媒體物件 (photo, video, etc...) 都有一個 object_id,查詢每個媒體物件的 object_id 用以查詢該媒體物件的 comments。
        • post_id
        • fromid
          • 誰 post 此則 comment。
        • time
        • text
        • id
        • username
        • reply_xid

        [FQL] Stream

        Ref: http://wiki.developers.facebook.com/index.php/Stream_%28FQL%29

        • post_id
          • stream 當中每則消息的 handle,透過他可以針對stream當中的物件下comment (Stream.addComment 方法)
        • viewer_id
        • app_id
        • source_id
          • 將此欄位放在 WHERE 之後可以篩選某人的塗鴉牆資料,並可以進一步限制 actor_id 取得該人塗鴉牆當中屬於自己的 post
        • updated_time
          • stream 當中每則消息的更新時間, 包括 comments 和 likes
        • created_time
        • filter_key
          • filter_key 要從 stream_filter Table 取得。透過 filter_key 可以自訂取出 stream 的類別 (預設的類別如: 近況更新、轉貼連結、相片、等等...,也能篩選出使用者自行定義的類別如: 國中同學、同事、等等...)。
          • 要如何取得特定類別的 filter_key,可以透過 stream_filter 當中的 icon_url 欄位觀察各類別的 icon 檔名,例如: 要取得 photo 類別的 filter_key,可以查詢 icon_url 當中是否包含 photo.gif 字串。
        • attribution
        • actor_id
          • 每則消息的發言人是誰。
        • target_id
        • message
        • app_data
        • action_links
        • attachment
          • 此欄位當中有 標籤可以判斷消息是屬於何種類型 (photo, link, video, etc...)
        • comments
        • likes
        • privacy
        • type
        • permalink
        • tagged_ids
        • is_hidden

        12/14/2009

        [note] soshow 朋友圈親密度

        分析自己和所有朋友的親密度,做一個 泡泡關係圖,越疏遠的泡泡距離越遠

        親密度如何判斷: 自己在對方的 post 當中說讚 和 留言的次數...

        K哥: 
        距離遠近代表朋友對你的態度: 泡泡越近代表對方越理你,泡泡越遠代表對方不鳥你
        泡泡大小代表你對朋友的態度: 泡泡越大代表你越理對方,泡泡越小代表你越不鳥對方

        12/13/2009

        [note] soshow think

        無法針對單張相片下comment 的問題依然無法解決,讓當初想要以 留言為互動性強化的動機 也大大的減弱,應該思考一下單張照片上的留言是否為互動性的主要角色。

        或者可以藉由取的每個 friend 的 uid 當作 stream table 的 source_id,用來將每個朋友塗鴉牆上的內容擷取出來,在判斷為 status 或者 photo。但是從 stream 當中撈到的 tagged photo,在 comment tag 當中的 can post 欄位是 0,也無法在 stream 針對tagged photo 下 comment

        12/11/2009

        How to sort two List object in the same way

        問題:

        我有兩個 List 物件 A 和 B,其元素為一對一的對應關係,我希望排序 A 的時候 B 當中的元素也能按照相同的排序方式排序。

        解法:

        創建一個物件 C,在此物件中宣告兩個欄位,一個放 A 的元素、一個放 B 的元素,這個物件必須繼承 IComparable 介面,並且實做 CompareTo 方法。

        然後建構一個 C 的陣列,將 A 和 B 的元素依序填入 C 陣列當中,再用 Sort 方法,即可將 陣列當中的 C 物件,依照指定的欄位排序。排序完成後,再用迴圈將 C 物件當中的欄位取出,填回 A 和 B。

        參考資料: http://aspalliance.com/1677_Sorting_an_Array_of_Custom_Objects_in_C.all

        12/09/2009

        [note] 091209

        Progress:

        1.
        FQL Table "stream" 當中的 source_id 可以指定要去撈取哪一個朋友的塗鴉牆,但是塗鴉牆上面的內容不一定是該朋友發布的,這時候要指定 actor_id 這個欄位為該朋友 id 來濾掉其他人的發布。

        另外,抓取某朋友的塗鴉牆不一定只有 "近況更新" 的訊息會被抓出,包括 "轉貼連結" 等等東西也會被抓出來,因此透過判斷 attatchment 欄位中的 type 欄位 過濾掉那些非 "近況更新" 的 stream

        2.
        * LIMIT 這個限制 Query reture 資料筆數的 command 要擺在最後面才會 work

        3.
        使用 List 添加 new element 時,使用 List.Add 的函式,由於 List 是 reference type 所以並非複製一份參數物件加入,因此如果在添加完畢後消除該物件,List 當中的物件也會跟著消失:

        List.Add(obj A);
        A.clear()

        因此,如果希望是以 value type 的方式添加 List element 那麼要採用 new 的方式:

        List.Add(new A());

        Action:

        建構 Tag 部分的三層架構 (subject 當中有很多 pid,每個 pid 當中有很多 comment)

        12/08/2009

        [note] 091208

        Progress:
        status 的兩種模式 Archive 和 Updated 模式初步完成,均透過使用者自己的 stream Table 撈取。

        Archive:

        1. Load 所有的朋友 ID 進來
        2. "SELECT {0} FROM stream WHERE source_id IN () LIMIT 10" 這邊的 source_id 指的是去該 id  使用者的塗鴉牆去擷取資料,該塗鴉牆上面的資訊,不一定都是該使用者發布的。
        若是想透過 WHERE filter_key = statusKey AND source_id = 結合兩個條件去從自己的 "近況更新" 當中抓取 source_id 使用者的發言,結果會是失敗的! 實際上直行的結果,這樣的查詢與 WHERE source_id = 無異

        Update:
        1. 首先都要先找出 "近況更新" 的 filter_key。
        2.1 所有的
        按照時間 (最新更新的時間) 濾出"近況更新"。

        2.2 我的
        按照時間 (最新更新的時間) 濾出我的 "塗鴉牆"。

        2.3 我回覆過的
        按照時間 (最新更新的時間) 濾出我回覆過的 "近況更新"。

        Think:
        雖然可以透過一些手段找到 "近況更新" 的 filter_key 但是,要在 "近況更新" 當中濾出某個特定朋友的 post 卻沒有直接的方法,本來以為 source_id 這個欄位可以,但是其實他是取抓該 id 的塗鴉牆,而塗鴉牆上的東西不一定單單是 status,實在很令人苦惱 Orz...

        Action:
        繼續 Photo 的部分,並看看上面的問題有無解法...

        12/07/2009

        [note] 091207

        Note:
        實做部分有兩大主題: status 和 photo
        兩者都有兩種模式 archive & updated 

        Progress:
        今天下午將 status 的 updated 模式大致完成,要針對 FQL 的 stream Table 單取 status 的 filter 沒有直接的做法,也就是說無法在 WHERE 內下條件單是選取 attachment 的 type 欄位是 "status" 的 stream

        因此先去出 type = "application" 的 filter_key (但是不只 status 屬於 "application" type, link, photo 和 video 等等都是),然後在一一測試用該 filter_key 選出來的 stream 當中 attachment 的 type 欄位是不是空的,如果是空的那麼該 stream 就是 status,並記錄下該 filter_key

        Think:
        只要該 stream 一有更新便會 pop 到最上面,如果遇到不太熟的朋友但是被回應一大堆,然後該篇 post 一直佔據著置頂似乎不太直覺。會不會使用者比較關心的是自己有回應過的 status....

        Action:
        完成每一個單獨 updated status 的 class,當中可以增加一個欄位為是否有自己的 "留言" 或 "讚"。archive 模式或許可以直接從 FQL 的 "status" Table下手,當中的 time 欄位為是否為 "new" 的依據,並且在本機端存下備份。



        12/04/2009

        [memo] soshow 討論結果 - 1

        四大類別: status, browsing, tag, comment

        status: 每個朋友最近n筆近況更新 和 依照最新發布時間的順序
        browsing: 傳統的檔案系統瀏覽模式 和 依照最新上傳時間的順序
        tag: 依照朋友濾出該朋友所有被標籤的相片 和 依照最新標籤時間的順序
        comment:

        每個類別有 bird view 和 stream view 兩種呈現方式

        bird view: 以頭像為主的呈現方式
        stream view: 類似 twitter 的時間流方式

        12/02/2009

        [Ques] 如何 ORDER BY 特定欄位的順序

        假設 table "TEST" 有欄位 a = {1, 2, 3, 4} 對應之 b = {5, 6, 7, 8}

        SELECT a FROM TEST WHERE b = {7, 6, 5, 8} 出來的結果會是 a = {3, 2, 1, 4} 嗎 ?

        有什麼語法可以達成這個目的嗎?

        12/01/2009

        [C#] xml 中 url 的 special characters

        透過 API 抓取的 xml 欄位中若有網址的資料,當中會有 escape 字元,須經過處理將這些 escape 字元去除

        public static string EscapeXml( this string s )
        {
        string xml = s;
        if ( !string.IsNullOrEmpty( xml ) )
        {
        // replace literal values with entities
        xml = xml.Replace( "&", "&amp;" );
        xml = xml.Replace( "&lt;", "&lt;" );
        xml = xml.Replace( "&gt;", "&gt;" );
        xml = xml.Replace( "\"", "&quot;" );
        xml = xml.Replace( "'", "&apos;" );
        }
        return xml;
        }
        
        public static string UnescapeXml( this string s )
        {
        string unxml = s;
        if ( !string.IsNullOrEmpty( unxml ) )
        {
        // replace entities with literal values
        unxml = unxml.Replace( "&apos;", "'" );
        unxml = unxml.Replace( "&quot;", "\"" );
        unxml = unxml.Replace( "&gt;", "&gt;" );
        unxml = unxml.Replace( "&lt;", "&lt;" );
        unxml = unxml.Replace( "&amp;", "&" );
        }
        return unxml;
        }

        參考資料: http://www.csharper.net/blog/escape_xml_string_characters_in_c_.aspx

        11/26/2009

        [C#] 移除 List 當中重複的物件

        Private List<string> removeDuplicates(List<string> inputList) {
           
            Dictionary<string, int> uniqueStore = new Dictionary<string, int>();
            List<string> finalList = new List<string>();
          
            foreach (string currValue in inputList) {
                if (!uniqueStore.ContainsKey(currValue)) {
                    uniqueStore.Add(currValue, 0);
                    finalList.Add(currValue);  
                }
            }
           
            return finalList;
        }
        
        

        [FB API] indexable column myth, lol

        FQL wiki 頁面說: Another key restriction is that your query must be indexable.

        也就是說在用 FQL 下條件的時候 (WHERE 後面的欄位) 必須要是 indexable 的才可以,該欄位是否可以 indexable 在 FQL table 當中有註明

        測試過後,如果在非 indexable 的欄位前面加上 可以 indexable 的欄位, 有時候會行的通 lol

        11/24/2009

        [note] 091123

        Q: 如何得知上一次 User 已經看過哪些 updated item ?

        A: 介面以單張呈現的話,依 舊 -> 新 的順序呈現,並記住 user 離開介面的時候該張圖片的 updated_time,下一次撈 updated 就從該時間點開始。

        11/20/2009

        [FB API] FQL 欄位筆記 091120

        用 FQL 抓 album 的 object_id 可行,抓到 object_id 就可以針對該相簿把該相簿的所有 comment 抓出

        var query = string.Format("SELECT object_id FROM album WHERE owner IN ({0})", self.uid);
        
        var query1 = string.Format("SELECT text FROM comment WHERE object_id IN ({0})", query);
        var result = service.Api.Fql.Query(query1);
        

        考慮到要針對特定 Album 或 Photo 加 comment 的話,利用 Comment.Add 的方法,需要參數 post_id,但是透過 FQL 去 SELECT post_id 這個欄位的時候,會是空的,起初以為是沒有發布到 Stream 上面的相簿所以沒有,經查證後結論是 comment 的 post_id 欄位全都抓不到

        轉而利用 FQL 抓取 stream,利用 updated_time 和 created_time 的差異來得知該 post 有備更新過 (wiki 上面的說法是只要被 comment 或 like 都算是 update),但經驗證後發現,只有 comment 會讓 updated_time 欄位更新

        11/18/2009

        Unix Time 轉 .Net DateTime

        透過 Facebook API 拿到 Stream 當中的時間單位是 Unix Time 格式
        因此對應到 .Net 上必須轉換,這樣搜尋時才會 locate 到正確的時間點
        參考資料: http://www.snippetit.com/2009/04/c-unix-time-to-net-datetime-and-vice-versa/

        using System;
        
        namespace snippetit.sample
        {
        struct UnixTime
        {
        private static DateTime BEGIN_UTC = new DateTime(1970, 1, 1);
        private long utValue;
        
        public UnixTime(long seconds)
        {
        utValue = seconds;
        }
        
        public UnixTime(DateTime dateTime)
        {
        this.DateTime = dateTime;
        }
        
        public long Value
        {
        get { return utValue; }
        set { utValue = value; }
        }
        
        public DateTime DateTime
        {
        get { return BEGIN_UTC.AddSeconds((long)utValue); }
        set { utValue = (long)((TimeSpan)(value - BEGIN_UTC)).TotalSeconds; }
        }
        
        public override string ToString()
        {
        return DateTime.ToString("yyy-MM-dd HH:mm:ss"); ;
        }
        }
        }

        將 UnixTime 轉成 long: http://www.digitalcoding.com/Code-Snippets/C-Sharp/C-Code-Snippet-Convert-Unix-timestamp.html

        11/17/2009

        [memo] webcam 分析膚色輔助化妝

        妝要畫的好是一門深奧學問,過與不及都是失敗

        如果有一個專家評等系統,可以透過 webcam 的影像來評估

        提示什麼區域可能需要加強或減少,不知道有沒有賣點