2015年9月12日 星期六

C# equals

之前考試遇到的題目,覺得==、equlas這兩者到底預設使用什麼比較蠻重要的觀念,所以還是來記錄一下。

class Test
{
public int field = 10;
}
Test test1 = new Test();
Test test2 = new Test();

  1. test1 == test2  => false
    因為Reference type的==,根據預設會藉由判斷兩個參考是否表示相同的物件,以測試參考是否相等,所以代表預設應該是使用類似object.ReferenceEquals來比較兩者的reference是否相等。
  2. test1.Equals(test2) => false
    同1,預設也是檢查參考
  3. object.ReferenceEquals(test1, test2) => false

知道reference的==和equlas預設是使用什麼,接下來只要分別你的data type是value type還是reference type就好。 而大家一般搞混string的是它其實是reference type,只是它implements ==和Equals function會比較字串的值。 基本上上面就解決大部分的問題,後來看到這篇所提到的boxing,也是相當需要注意的。Boxing概念主要就是把數值轉成object,所以就看轉成的object,因為轉成object就是reference type了,也因為==必須標明實際的data type,所以如果是object==object,則當然就是預設檢查reference。但注意如果Unboxing的話==則自然就變成value==value了。

最後唯一的例外一樣是同一篇提到的,字串的常數,照理說字串是reference,宣告兩個相同值的字串常數用成object type,檢查==應該就是檢查reference,可是CLR存在著一種機制,當它初始化時,它會創建一個內部hash,其中key是我們所要存放的字串,而value是誰引用。當定義一個新的string 時,系統會檢查是否有相同的。如果找不到,就建立一個新的,如果找到就直接引用。所以object type兩個字串的常數,reference會是相同的,真是麻煩………..

2015年6月13日 星期六

Warning when Resolving Conflicts in Git

因為在公司出過兩次包了,覺得自己實在太智障了,為了嚴逞自己的錯誤,所以來這邊紀錄一下,希望有看到的人不要再跟我一樣。
基本上處裡Conflict的過程可以看到"連猴子都能懂的Git入門指南"的這兩篇 合併修改紀錄解決衝突
簡單說明一下情境:

  1. 大概有一段時間沒有跟遠端伺服器做合併的動作,只有Commit自己修改的東西到Local Reposity。
  2. 突然某天想Pull和Push跟遠端伺服器同步一下,結果發現有衝突了,基本上應該是Local Reposity和遠端伺服器上的Reposity兩邊有修改到相同的檔案,Git不知道該怎麼自動把遠端伺服器上的紀錄合併到自己的Local Reposity?
  3. 這時就得自己手動合併,重點來了,手動合併老實說是相當危險的事。然後注意這時在處理衝突的動作,都是在Working Copy的動作。衝突Resolve後,必須再Commit到Local Reposity上,最後再Push到遠端伺服器。
    注意:這時要解決衝突,一定會打開修改過檔案的列表視窗(TortoiseGit叫Check for modification),這時會發現莫名一堆檔案是被修改過的,而且不是自己改的。這些就是你當前Local Reposity和遠端伺服器上的Reposity的差異檔案,
    千萬不要把他們Revert!!千萬不要把他們Revert!!千萬不要把他們Revert~~~~
    我因為有潔癖,覺得Git怎麼會亂改我Working Copy的東西,覺得很不爽的全都Revert了之後,Commit加Push。隔天就出現哀嚎聲……
    照理說這些差異檔案,一般沒出現衝突的話,其實Git會自動幫你合併並Commit到你的Local reposity,如果Pull完後再看Git Log的話,就會發現一個Commit的log紀錄。所以如果當出現衝突後,Git無法知道怎麼合併,自然就只能把遠端檔案修改到Working Copy之後,由使用者自己決定哪些資料要合併,並且由使用者自己Commit合併之後的差異檔案到Local Reposity。
    如果在這時你把合併的資料Revert或亂搞,Commit並Push,因為你做了合併的動作,所以Git認為你的資料才是最新的,所以當你Push到遠端伺服器後,遠端伺服器的Reposity自然就會以你的更動為主,所以自然而然的遠端伺服器的資料也跟著被Revert或亂搞了。
  4. 最後結論就是,建議Pull之前先備份Working Copy內修改過的檔案,可以做Stash或者自己手動備份,不然Pull合併後看哪些要Commit就很麻煩,然後只處裡衝突的檔案就好,不要傻傻亂動其他人的東西…………

以上就是我搞爆公司Git的經歷與心得,希望有機會幫到看到這篇的人T_T

Unity render order

基本上Unity render的順序主要由三個地方來依序檢查:

  1. Camera Depth: camera render 順序,Depth越小代表越先畫,而Depth越大的Camera,一律蓋在Camera Depth小的object上面。
    image 
    那Camera會畫哪些東西由Culling Mask決定,所以每個gameObject所選的那些Layer層,只是Camera用來Group哪些gameObject該畫,哪些不該畫。
    image
  2. Render Queue: 代表gameObject在當前Camera內畫的順序,RenderQueue越小的越先畫,而後畫的一定都蓋在先畫的上面。可由Shader或Material指定。
    預設都由Shader指定,Material的RenderQueue會直接以Shader指定的作為預設。
    http://docs.unity3d.com/Manual/SL-SubShaderTags.html
    也可由程式抓到gameObject.render的Material來指定自己的RenderQueue
  3. http://docs.unity3d.com/ScriptReference/Material-renderQueue.html
  4. Transform position的z值: 當以上1和2都相同的話,則就比對Z值。那Z值誰大誰小造成誰先畫,則看你Camera朝向的方向了。反正通常越靠近鏡頭的越先畫。

通常一般UI或3D object其實都可以使用相同的RenderQueue去畫,再調Z值就好。 可是像有些Particle System希望一定要蓋到UI上,而且Unity的Particle System不能控制Particle要移動多少Z值,所以常常穿插在UI或3D object中間,造成閃爍問題(因為Z值靠太近)。這種時候一定要有個Script動態可以去調整RenderQueue,才可以蓋在所有東西的上面。

那目前許多公司都用NGUI(3.x版),雖然每個UIWidget都是用它自己所謂的Widget depth來調整,但是它事實上還是自已用RenderQueue來管理,可以使用它的Drawcall Tool來看它每個Panel底下所畫的Widget的RenderQueue
imageimage

2015年3月24日 星期二

Monobehaviour Execution Order of Event Functions

今天考試又被問到對Unity從來沒有查明的問題,就是Monobehaviour裡面原本被已經決定好的function的執行順序,像是Awake或者Start之類的,原本以為只有一些簡單的Awake、Start、OnEnable、Update、OnDisable、OnDestroy這幾個,查一下Unity官網,想不到還真多。
唯一讓我覺得奇怪的是Start竟然比OnEnable晚,真是奇怪.....

2015年3月9日 星期一

C# value type or reference type

在C# type內有些data type常常搞錯,不知道是value type或者reference type,因為考試又被電一次,在這備註一下。
主要是reference type才有可能為null。

string testValue;
if(testVlaue != null)
{
//是否會進來
}
在這邊因為string是reference type,只是他的operator"="被改寫成是用copy value的方式,看起來很像value type。所以這邊的if不會進來。


decimal testValue;
if(testVlaue != null)
{
//是否會進來
}
decimal是value type所以這個if永遠都會進來。

DateTime testValue;
if(testVlaue != null)
{
//是否會進來
}
DateTime這個data type也是令人意外的type,他是value type,所以這個if永遠都會進來。

int? testValue;
if(testVlaue != null)
{
//是否會進來
}
這個int?就是reference type,所以這個if不會進來。

Tread start problem

今天考試被電了一回,題目是
public class A
{
    public int count = 0;
    public void AddCount(int value)
    {
        count += value;
    }
}

public void test()
{
    A recordA = new A();
    Threand thread = new Thread(delegate()
    {
        recordA.AddCount(1);
    }

    thread.Start();
    recordA.AddCount(1);
}

這邊是因為thread.Start()時,就有可能和下一行recordA.AddCount(1);同時執行,並且在拿count這個變數的值時,有可能都拿到相同的值。所以這邊應該在AddCount function內加lock。

2014年11月4日 星期二

Unity script hash code not compatible

1. prefab attach的script更新之後,將prefab包成Asset bundle,包出去之後。下次包版時,script有異動,但是即使Untiy 做Save project的動作,都不會造成prefab本身有任何異動,所以只有script再包出去,結果新的程式讀到舊的AssetBundle,就會造成錯誤。Untiy報的錯誤是 script hash code not compatible。