<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>C# on 終於明白 | tsungyi knows.</title><link>https://tsungyi.li/Blog/tags/c%23/</link><description>Recent content in C# on 終於明白 | tsungyi knows.</description><generator>Hugo</generator><language>en-us</language><lastBuildDate>Fri, 06 Dec 2019 03:41:00 +0800</lastBuildDate><atom:link href="https://tsungyi.li/Blog/tags/c%23/index.xml" rel="self" type="application/rss+xml"/><item><title>Unity - Null &amp; Missing Reference Validator</title><link>https://tsungyi.li/Blog/posts/unity-null-and-missing-reference/</link><pubDate>Fri, 06 Dec 2019 03:41:00 +0800</pubDate><guid>https://tsungyi.li/Blog/posts/unity-null-and-missing-reference/</guid><description>&lt;h2 id="notnullattribute"&gt;NotNullAttribute&lt;/h2&gt;
&lt;p&gt;在 Unity 中如果想要在編譯期增加驗證，確保 GameObject 必須要設定好參考，避免沒有設定好參考執行時出錯。我們可以用一個自訂的 &lt;code&gt;Attribute NotNullAttribute&lt;/code&gt; 來標注需要檢查的成員。並且增加一個檢查函式來檢查參考是否為空。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;[AttributeUsage(AttributeTargets.Field)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;NotNullAttribute&lt;/span&gt; : Attribute
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;使用的方式只要在 GameObject 的成員加上 [Not Null] 即可&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;注意！&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;這個檢查，目前只適用在 GameObject 及其子類別的成員。至於其他 Reference Type 的成員（也就是 SerializeField 的成員）。因為 Unity 的 Serialization 機制所致， Reference Type 的成員不會是 null。所以 NotNull 的檢查永遠不會生效。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;TestMonoBehaviour&lt;/span&gt; : MonoBehaviour
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt; [NotNull, SerializeField]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; GameObject notNullPrivateItem;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt; [NotNull, SerializeField]&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; GameObject notNullPrivateItem_Null;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt; [SerializeField]&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; GameObject privateItem;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt; [SerializeField]&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; GameObject privateItem_Null;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt; [NotNull]&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; GameObject notNullPublicItem;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt; [NotNull]&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; GameObject notNullPublicItem_Null;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; GameObject publicItem;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; GameObject publicItem_Null;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="postprocessbuild"&gt;PostProcessBuild&lt;/h2&gt;
&lt;p&gt;另外我們需要一個 PostProcessBuild 來進行驗證，其中的 CheckAllEnabledScenes 跟 CheckAllPrefabs 用來從所有的 Scenes 以及 Prefabs 之中檢查所有的 Components。&lt;/p&gt;</description></item><item><title>Unity - 使用 Null Condition Operator &amp; Null Coalescing Operator</title><link>https://tsungyi.li/Blog/posts/unity-null-condition-operator-and-null-coalescing-operator/</link><pubDate>Mon, 16 Sep 2019 20:35:00 +0800</pubDate><guid>https://tsungyi.li/Blog/posts/unity-null-condition-operator-and-null-coalescing-operator/</guid><description>&lt;p&gt;&lt;strong&gt;Null Conditional Operator&lt;/strong&gt; 跟 &lt;strong&gt;Null Coalescing Operator&lt;/strong&gt; 都是 C# 6.0 的新語法，可以讓你寫出更加精簡而且可讀性佳的語法。但是在 Unity 中使用需要特別注意，在某些情況下，執行結果可能跟你想的不一樣。&lt;/p&gt;
&lt;h2 id="null-condition-operator"&gt;Null Condition Operator (&lt;code&gt;?.&lt;/code&gt;)&lt;/h2&gt;
&lt;p&gt;當 &lt;code&gt;?.&lt;/code&gt; 的左側是 &lt;code&gt;null&lt;/code&gt; 就不會執行右側的語法，如此就可以移除掉很多 &lt;code&gt;null&lt;/code&gt; 檢查讓我們的程式更加簡潔好讀。&lt;/p&gt;
&lt;p&gt;先看一下不使用 &lt;strong&gt;Null Conditional Operator&lt;/strong&gt; 的情況：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; text = &lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;.Empty;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (m_controller != &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (m_controller.m_display != &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (m_controller.m_display.m_text != &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; text = m_controller.m_display.m_text.text;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果使用 &lt;strong&gt;Null Conditional Operator&lt;/strong&gt; 的話，可以改寫成以下的語法：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; text = m_controller?.m_display?.m_text?.text;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (text = &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; text = &lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;.Empty;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果其中任何一部份回傳值為 &lt;code&gt;null&lt;/code&gt;，text 最後的結果就是最後結果的預設值 (default)。對於參考型別來說就是 &lt;code&gt;null&lt;/code&gt; 了，值型別就是 &lt;code&gt;0&lt;/code&gt; 或 &lt;code&gt;false&lt;/code&gt;。&lt;/p&gt;</description></item><item><title>Unity - 存取修飾詞 (Access Modifier) 與 Special folders &amp; Assembly definition files</title><link>https://tsungyi.li/Blog/posts/unity-access-modifier/</link><pubDate>Mon, 12 Nov 2018 01:50:00 +0800</pubDate><guid>https://tsungyi.li/Blog/posts/unity-access-modifier/</guid><description>&lt;h2 id="存取修飾詞-access-modifier"&gt;存取修飾詞 Access Modifier&lt;/h2&gt;
&lt;p&gt;C# 的存取修飾詞有以下六種&lt;/p&gt;
&lt;dl&gt;
&lt;dt&gt;&lt;code&gt;public&lt;/code&gt;&lt;/dt&gt;
&lt;dd&gt;所有人都可以存取&lt;/dd&gt;
&lt;dt&gt;&lt;code&gt;protected&lt;/code&gt;&lt;/dt&gt;
&lt;dd&gt;只有所在類別以及他的的衍生類別可以存取&lt;/dd&gt;
&lt;dt&gt;&lt;code&gt;private&lt;/code&gt;&lt;/dt&gt;
&lt;dd&gt;只有所在類別可以存取&lt;/dd&gt;
&lt;dt&gt;&lt;code&gt;internal&lt;/code&gt;&lt;/dt&gt;
&lt;dd&gt;只有在相同 assembly 的類別可以存取&lt;/dd&gt;
&lt;dt&gt;&lt;code&gt;protected internal&lt;/code&gt;&lt;/dt&gt;
&lt;dd&gt;只有在相同 assembly 的類別或是所在類別以及他的的衍生類別可以存取
(也就是 protected OR internal)&lt;/dd&gt;
&lt;dt&gt;&lt;code&gt;private protected&lt;/code&gt; (C# 7.2 新增)&lt;/dt&gt;
&lt;dd&gt;只有在相同 assembly 的類別以及所在類別以及他的的衍生類別可以存取
(也就是 protected AND internal)&lt;/dd&gt;
&lt;/dl&gt;
&lt;p&gt;從這張簡圖就很容易了解不同修飾詞的範圍
&lt;img src="https://tsungyi.li/Blog/images/Unity-Access-Modifier/access-modifier.png" alt="修飾詞的範圍"&gt;&lt;/p&gt;
&lt;p&gt;另外 Type 只能宣告為 &lt;code&gt;public&lt;/code&gt; 或 &lt;code&gt;internal&lt;/code&gt;，Type Member 可以用所有的存取修飾詞宣告。&lt;/p&gt;
&lt;h3 id="default-access-modifier"&gt;Default Access Modifier&lt;/h3&gt;
&lt;p&gt;預設值總是可見度最低的存取修飾詞。Type 為 &lt;code&gt;internal&lt;/code&gt;，Type Member 為 &lt;code&gt;private&lt;/code&gt;。&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;&lt;/th&gt;
					&lt;th&gt;&lt;strong&gt;預設的存取修飾詞&lt;/strong&gt;&lt;/th&gt;
					&lt;th&gt;&lt;strong&gt;可用的存取修飾詞&lt;/strong&gt;&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;namespace level&lt;/strong&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;enum&lt;/td&gt;
					&lt;td&gt;internal&lt;/td&gt;
					&lt;td&gt;public, internal&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;interface&lt;/td&gt;
					&lt;td&gt;internal&lt;/td&gt;
					&lt;td&gt;public, internal&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;class&lt;/td&gt;
					&lt;td&gt;internal&lt;/td&gt;
					&lt;td&gt;public, internal&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;struct&lt;/td&gt;
					&lt;td&gt;internal&lt;/td&gt;
					&lt;td&gt;public, internal&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;delegate&lt;/td&gt;
					&lt;td&gt;internal&lt;/td&gt;
					&lt;td&gt;public, internal&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;type level&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;enum&lt;/td&gt;
					&lt;td&gt;private&lt;/td&gt;
					&lt;td&gt;public, protected, internal, private, protected internal, private protected&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;interface&lt;/td&gt;
					&lt;td&gt;private&lt;/td&gt;
					&lt;td&gt;public, protected, internal, private, protected internal, private protected&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;class&lt;/td&gt;
					&lt;td&gt;private&lt;/td&gt;
					&lt;td&gt;public, protected, internal, private, protected internal, private protected&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;struct&lt;/td&gt;
					&lt;td&gt;private&lt;/td&gt;
					&lt;td&gt;public, protected, internal, private, protected internal, private protected&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;delegate&lt;/td&gt;
					&lt;td&gt;private&lt;/td&gt;
					&lt;td&gt;public, protected, internal, private, protected internal, private protected&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;enum value&lt;/td&gt;
					&lt;td&gt;public&lt;/td&gt;
					&lt;td&gt;public&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;interface member&lt;/td&gt;
					&lt;td&gt;public&lt;/td&gt;
					&lt;td&gt;public&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;class member&lt;/td&gt;
					&lt;td&gt;private&lt;/td&gt;
					&lt;td&gt;public, protected, internal, private, protected internal, private protected&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;struct member&lt;/td&gt;
					&lt;td&gt;private&lt;/td&gt;
					&lt;td&gt;public, internal, private&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;以軟體設計的原則，應該讓類別、變數的可見性最小化。也就是說不需要公開的類別就不應該設為 &lt;code&gt;public&lt;/code&gt;。&lt;/p&gt;</description></item><item><title>Unity - 忽略警告訊息</title><link>https://tsungyi.li/Blog/posts/unity-ignore-warning/</link><pubDate>Wed, 07 Nov 2018 15:49:00 +0800</pubDate><guid>https://tsungyi.li/Blog/posts/unity-ignore-warning/</guid><description>&lt;p&gt;在 Unity 中如果有用到其他 Plugins 經常會發現許多來自這些 Plugins 的 Warning。如果不處理的話，這些訊息可能會淹沒了專案中真正需要注意的警告訊息。&lt;/p&gt;
&lt;p&gt;底下是來自我們目前專案的警告訊息：&lt;/p&gt;
&lt;p&gt;Unity 看到的警告訊息大約 300個
&lt;img src="https://tsungyi.li/Blog/images/Unity-Ignore-Warning/Warning-1.png" alt="Unity 看到的警告訊息大約 300個"&gt;&lt;/p&gt;
&lt;p&gt;從 Visual Studio for Mac 看到的警告訊息超過 2000個
&lt;img src="https://tsungyi.li/Blog/images/Unity-Ignore-Warning/Warning-2.png" alt="從 Visual Studio for Mac 看到的警告訊息超過 2000個"&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;: Unity 跟 Visual Studio for Mac 的警告訊息數量不同，最好兩個都檢查&lt;/p&gt;
&lt;p&gt;雖然理論上警告訊息都必須要修正，但是專案進行中總是有很多無法掌握的情形，
以下介紹我在目前處理的專案中，遇到難以修改的警告訊息的解決方式：&lt;/p&gt;
&lt;h2 id="plugins-warning"&gt;Plugins&amp;rsquo; warning&lt;/h2&gt;
&lt;p&gt;對於第三方的 Plugins 我們可以先用 &lt;code&gt;#pragma warning&lt;/code&gt; 命令來暫時關閉警告訊息。&lt;/p&gt;
&lt;p&gt;關閉的方式使用 &lt;code&gt;#pragma warning disable&lt;/code&gt; 暫時關閉，並在使用後用 &lt;code&gt;#pragma warning restore&lt;/code&gt; 開啟警告。&lt;/p&gt;
&lt;p&gt;通常會在發生警告前一行加上 &lt;code&gt;#pragma warning disable *warning-list*&lt;/code&gt;，並且在發生警告後一行加上 &lt;code&gt;#pragma warning restore *warning-list*&lt;/code&gt; 重新開啟警告。&lt;/p&gt;
&lt;p&gt;一般來說，建議將關閉警告與開啟警告的範圍越小越好，避免意外隱藏其他有意義的警告訊息。&lt;/p&gt;
&lt;p&gt;如果檔案裡的警告太多，也可以在檔案開頭與結尾分別加上關閉與還原檔案內所有警告訊息。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;: 這樣的關閉方式，一但更新 Plugins 的時候可能要重新處理一次。&lt;/p&gt;</description></item></channel></rss>