iT邦幫忙

2

static vs const vs singleton 問題

c#

static vs const vs singleton 問題

這天小明來問甚麼是 static , 甚麼時候該用 static ? const 跟 static readonly 有什麼差別 ?

首先我們建立一個 DLL Project, 叫做 Example.dll

public class Example
{
   public const string ConstString = "1";
   public static readonly string ReadonlyString = "1";
}

接著我們建立一個 Console Project, 叫做 Hello.exe,

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine($"ConstString = {Example.ConstString}");
        Console.WriteLine($"ReadonlyString = {Example.ReadonlyString}");
    }
}

https://ithelp.ithome.com.tw/upload/images/20200602/20119139F8w2UweDSP.png

這支 Hello.exe 引用參考 Example.dll , (不要直接參考 Example.csproj 專案) , 沒有意外的話, Output 結果應該如下

ConstString = 1
ReadonlyString = 1

但現在我們再一次修改 Example.cs , 並重新發布 Example.dll 給 Hello.exe 用

public class Example
{
   public const string ConstString = "2";
   public static readonly string ReadonlyString = "2";
}

https://ithelp.ithome.com.tw/upload/images/20200602/20119139NgT2RqFfzF.png

大部分的人都會回答 Output 都是 2 , 但卻落入一個陷阱, 程式依然能正常執行,但 Output 實際上結果會是如下

ConstString = 1
ReadonlyString = 2

這是因為 Hello.exe 在第一次被編譯時,就已經把所有用到 const 的內容帶入其中,沒有重新編譯的情況下,const 的內容都不會改變。
上述的 Hello.exe 內容會被 Compiler 編譯成如下的 IL 中繼語言程式碼

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine($"ConstString = 1");
        Console.WriteLine($"ReadonlyString = {Example.ReadonlyString}");
    }
}

static readonly 是比較建議的常數使用方法.
而 const 建議的使用時機大概有以下情況:

  • 內容必須要在編譯時期決定的時候
  • 永遠不會改變的內容, 例如能量守恆定律(像是圓周率3.141592, 身分證驗證規則)
  • 非常需要效能的時候

接著回答小明的第二個問題 "Static vs Singleton 的區別是什麼?"

首先小明很喜歡每次建立新的物件的時候, 甚至每一個方法, 通通都宣告 static , 每個物件都寫成如下

public static class StaticSampleClass
{
   public static void SayHello()
   {
   }
   public static void Test1()
   {
   }
}

因為小明認為在程式呼叫端, 只需要一行程式碼,

StaticSampleClass.SayHello(); 

不必進行 new 指令, 寫起來比較爽快

var obj = new StaticSampleClass();
obj.SayHello();

首先 static class and static method 有幾個問題

  • 無謂地佔住記憶體不放, 無論應用程式有沒有用到的, 都會在應用程式啟動的時候初始化
  • 測試不容易, 因為直接耦合, 無法進行單元測試
  • 無法享用物件導向設計的好處(繼承的重用與擴充、介面的可抽換性)

小明就馬上把 StaticSampleClass 裡面所有方法 method , 都把 static 關鍵字拔掉,
又嘗試加上

public static StaticSampleClass Instance = new StaticSampleClass();

小明完整的程式碼如下

public class StaticSampleClass
{
   public static StaticSampleClass Instance = new StaticSampleClass();
   public void SayHello()
   {
   }
   public void Test1()
   {
   }
}

而小明的呼叫端也改成如下

StaticSampleClass.Instance.SayHello();

看來看去也沒有比較好呼叫使用, 而且

無論應用程式有沒有用到的, 都會在應用程式啟動的時候初始化

而 Singleton是一種設計模式,可確保您的應用程序只建立一個實例.

public interface ISample
{
  void SayHello();
  void Test1();
}

public class SingletonSampleClass : ISample
{
  public void SayHello()
  {
  }
  public void Test1()
  {
  }
}

另一方面,很多語言都有提供 DI 以及 IOC 框架,這些框架可以幫你建立實例,
只要預先寫好物件的interface 即可。同時還可以幫你解決 Singleton 要做的事情,可以不用自己實作 。

可以在應用程式註冊之後, 只有當應用程式真正的需要此物件的時候再進行實例化(new).

serviceProvider.AddSingleton<ISample, SingletonSampleClass>();

註冊interface 完之後, 呼叫端也只需要簡單的一行

public class MyController
{
   public MyController(ISample sample)
   {
     sample.SayHello();
   }
}

圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言