2009-04-27 126 views
5

我想要一個將在程序啓動時自動實例化的單例。如何:在C#中自動實例化單例#

我的意思是「自動實例化」是Singleton中的代碼應該在程序啓動時實例化自己,而不需要其他代碼的任何調用或聲明。

所以我想類似以下實例並寫出「MySingleton實例化」在程序啓動(無主代碼做什麼)......

static class MySingleton 
{ 
    private static MySingleton self = new MySingleton(); 

    protected MySingleton() 
    { 
     System.Console.WriteLine("MySingleton Instantiated"); 
    } 
} 

除了這一點,因爲C#不工作會只在需要時初始化類的靜態成員,即當它們被訪問時等。

那麼我該怎麼做?這可以做到嗎?我還沒有親自用C++來做這件事(一段時間沒有使用C++),但我很確定它可以在C++中完成,但不知道C#。

任何幫助表示讚賞。謝謝。


什麼我確實想與此有關的是... 會有許多單身類(多可隨着時間的推移被添加),所有這些都從一個共同繼承(抽象)父類(又稱PClass)。

的PClass將有一個靜態成員是PClasses的集合......和構造將自身添加到集合...

然後在理論上所有的單身人士將自動地被添加到集合(因爲當它們被實例化時,基類的PClass構造函數被調用並且將新的對象添加到集合中)...然後可以在不知道什麼是子類(單例)類已經實現的情況下使用集合,並且可以使用新的子類(單例)類可以隨時添加,而無需更改任何其他代碼。

不幸的是,我不能讓孩子(單身人士)實例化自己......搞砸了我的小計劃,導致這篇文章。

希望我解釋得很好。


PS。是的,我意識到單身人士和他們的使用有不好的感覺......但他們有時是有用的,即使撒旦自己做單身人士,我仍然想知道我的問題是否可以在C#中實現。衷心感謝大家。

+2

撒旦是一個Singleton。 – 2009-04-27 23:17:02

回答

6

克里斯提到的IoC機制可能是最好的,但沒有說「最好」的解決方案,我能想到的是做一些時髦與反射和線沿線的屬性:

public class InitOnLoad : Attribute 
{ 
    public static void Initialise() 
    { 
     // get a list of types which are marked with the InitOnLoad attribute 
     var types = 
      from t in AppDomain.CurrentDomain.GetAssemblies().SelectMany(a => a.GetTypes()) 
      where t.GetCustomAttributes(typeof(InitOnLoad), false).Count() > 0 
      select t; 

     // process each type to force initialise it 
     foreach (var type in types) 
     { 
      // try to find a static field which is of the same type as the declaring class 
      var field = type.GetFields(System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic).Where(f => f.FieldType == type).FirstOrDefault(); 
      // evaluate the static field if found 
      if (field != null) field.GetValue(null); 
     } 
    } 
} 

[InitOnLoad] 
public class Foo 
{ 
    public static Foo x = new Foo(); 

    private Foo() 
    { 
     Console.WriteLine("Foo is automatically initialised"); 
    } 
} 

public class Bar 
{ 
    public static Bar x = new Bar(); 

    private Bar() 
    { 
     Console.WriteLine("Bar is only initialised as required"); 
    } 
} 

隨着調用InitOnLoad.Initialise()添加到您的主要方法。

您可以取消屬性,但這可能會導致不必要的類型被初始化並不必要地佔用內存(如上面的代碼中的Bar)。

還值得注意的是,這不會處理動態加載的任何程序集中包含的類型,除非您再次調用Initialise,但基於您的問題(「在程序啓動時自動實例化」),聽起來像是一個問題。

5

儘管.NET模塊理論上可以(IIRC)對模塊加載等作出反應,但這不是通過C#提供的。在一些框架(比如ASP.NET)中,可以通過配置使用鉤子,比如通過處理程序或通過global.asax.cs對其進行攻擊 - 但是,對於常規的C#應用​​程序(控制檯,winform等),您必須手動觸發它。例如,該類上的一個靜態構造函數將會被調用,該靜態構造函數將承載您的Main入口點。

那麼:這裏的用例是什麼?什麼時候懶惰的加載方法會不會好?

+0

我編輯了帖子以添加我的用例。 – devlop 2009-04-27 22:18:14

2

我懷疑這是可能的,但沒有從Main做任何事情。即使向該類添加static MySingleton() {},也不保證其實例化,如果您不使用它。

0

我不相信你想要的是.Net框架中可能的。基本上,您希望像運行時一樣通知類型或調用某些預定義的靜態方法,以便應用程序加載並運行或提供類似的機制。考慮開銷。運行時唯一確保的是自動調用程序的主入口方法。而已。在那裏你可以設置和初始化它們,但是沒有任何關於它的自動化。你仍然明確地將事情掛鉤並進行方法調用。

+0

我開始認爲這是不可能的,但它應該是! 我敢肯定它可以在C++來完成,雖然我還沒有真正做到了......雅顯然C#不是C++,但它的麻煩,這種類型的東西不能用C#來完成。 – devlop 2009-04-27 22:20:18

+0

我懷疑它甚至可能在C++中。我記得每個dll都有一些標準的回調函數,每次dll被加載,卸載,線程連接等都會被Windows調用,就像Mark Gravell提到的那樣,但即使如此,你也需要明確地初始化你的單例。另外,在.NET中,您無法訪問這些回調。可能有一種可能性是讓你自己的引導程序來託管.NET運行時。那麼你可以使用CLR託管API或一些伎倆來做你想做的事情,但爲什麼?我認爲你應該重新考慮你的設計和這個要求的必要性。 – 2009-04-27 23:15:54

1

您基本上要求.NET框架在加載程序集時調用某個函數。該功能將是PClass實例註冊商。

C#中沒有DllMain。你可以通過在你的main方法中有一個程序集級別的屬性和一些代碼來模擬這種情況,只要程序集被加載,它就會進行監聽。該屬性可以指定一個「DllMain」入口點或指向您的PCIass繼承類。

1

切線方向,請允許我指出,這通常不是單獨模式,因爲它通常是實現的。下面是在C#中的正常(簡體)執行(不包括這樣的東西線程安全爲簡潔):

public sealed class Singleton 
{ 
static readonly Singleton _instance = new Singleton(); 

// private ctor 
Singleton() {} 

public static Singleton Instance 
{ 
    get { return _instance; } 
} 
} 

這從您的代碼行甚至不應該編譯!

protected MySingleton() 

說了這麼多,我同意那個詢問你的用例的人。這很好理解。 =)

+0

雅,通常人們有一個實例訪問像你證明,但我的問題是,我不希望任何其他代碼直接訪問單......我只是希望它的實例在其自己的......所以沒有必要訪問者。 另外我編輯我的問題添加用例說明。 – devlop 2009-04-27 22:45:43

+0

順便說一句,受保護的構造函數有什麼問題。它編譯好。 – devlop 2009-04-27 23:20:46

+0

當您在靜態類中添加ctor(任何訪問級別)時,您應該會收到編譯器錯誤(「靜態類不能有實例構造函數」)。 – Garrett 2009-04-28 12:43:50

4

根據你要做的事情,我會放棄一個真正的Singleton的想法,並使用IoC庫來代替。

查看StructureMap,Castle Windsor,Ninject和/或Autofac。

這將允許您通過IoC庫創建類作爲單例,擁有儘可能多的,但它只是一個普通的舊類。

單身人士有一個問題,他們真的搞砸了應用程序的可測試性(通過單元測試)。

只是做一個谷歌搜索「Singleton認爲有害」,你會看到更多的參考。

或者,您也可以使用簡單的類工廠/方法工廠模式。

0

「的PClass將有一個靜態成員是PClasses的集合......」

聽起來似乎很容易與思考來完成。您不需要啓動時運行的代碼;只要你需要,你可以建立這些類的列表。

下面是一個例子,當您第一次讀取Instances屬性時,會加載列表一次,將查找當時加載的所有程序集(如果您只想查看與該程序集相同的程序集, PClass,但是你的問題並沒有指定你想查看哪個程序集),並且將任何PClass後代的單個實例(而不是PClass本身)添加到列表中。每個PClass後代都需要一個無參數的構造函數,但不需要任何類構造函數。

public class PClass 
{ 
    private static List<PClass> m_instances; 
    public static IList<PClass> Instances 
    { 
     get 
     { 
      if (m_instances == null) 
       m_instances = LoadInstanceList(); 
      return m_instances; 
     } 
    } 
    private static List<PClass> LoadInstanceList() 
    { 
     foreach (var assembly in AppDomain.GetAssemblies()) 
     { 
      foreach (var type in assembly.GetTypes()) 
      { 
       if (type.IsAssignableTo(typeof(PClass)) && type != typeof(PClass)) 
        m_instances.Add(Activator.CreateInstance(type)); 
      } 
     } 
    } 
}