2008-10-07 43 views
1

我在說c# 3.5 3.0。 我知道如何做到這一點,當緩存或ServiceProvider可以只有一個實例的整個應用程序。在這種情況下的ServiceProvider可以這個樣子ServiceProvider,高速緩存等用泛型完成,無需投入

public static class Service<T> 
{ 
    public static T Value {get; set;} 
} 

,可以用於不同類型的像這樣:

Service<IDbConnection>.Value = new SqlConnection("..."); 
Service<IDesigner>.Value = ...; 
//... 
IDbCommand cmd = Service<IDbConnection>.Value.CreateCommand(); 

靜態緩存也很容易:

public static class Cache<T> 
{ 
    private static Dictionary<int, T> cache = new Dictionary<int, T>(); 

    public static void Add(int key, T value) 
    { 
     cache.Add(key, value); 
    } 

    public static T Find(int key) 
    { 
     return cache[key]; 
    } 
} 

,並可以像使用這個:

Cache<string>.Add(1, "test"); 
Cache<DateTime>.Add(2, DateTime.Now); 
//... 
string found = Cache<string>.Find(1); 


我的問題是:如何創建類似的緩存或服務提供程序,當我想有兩個或更多不同的每個實例。下面是示例代碼,我要如何使用服務提供商:

ServiceProvider provider = new ServiceProvider(); 
provider.Add<IDbConnection>(new SqlConnection("...")); 
provider.Add<IDesigner>(...); 
//... 
ServiceProvider provider1 = new ServiceProvider(); 
provider1.Add<IDbConnection>(new SqlConnection("...")); 
//... 
//... 
IDbCommand cmd1 = provider.GetService<IDbConnection>().CreateCommand(); 
IDbCommand cmd2 = provider1.GetService<IDbConnection>().CreateCommand(); 

,我在我的頭使用鑄造,我想避免的唯一實現。

public class ServiceProvider 
{ 
    private Dictionary<Type, object> services = new Dictionary<Type, object>(); 
    public void Add<T>(T value) 
    { 
     services.Add(typeof(T), value); 
    } 

    public T GetService<T>() 
    { 
     return (T) services[typeof (T)]; 
    } 
} 

回答

2

你爲什麼特別想避免鑄造?是的,它感覺「不安全」 - 但基本上可以保證它不會成爲ServiceProvider中的問題,並且客戶端沒有進行任何投射。

這是一個相當普遍的問題,但我不相信在.NET泛型中有很好的解決方案 - 基本上這是一種無法表達的類型關係。

編輯:我現在有blogged關於這一點,並封裝在一個類型的行爲。如果它讓事情保持清潔,請隨時採取該代碼。

+0

考慮一下,這是一個非常常見的問題。我認爲有必要實現一個完全封裝這個部分的類型(字典添加/查找),以便將演員嚴格限制在單個類中。將實驗今晚並撰寫博客條目... – 2008-10-07 13:07:29

+0

從我在互聯網上發現的測試中看來,通用版本的代碼通常比使用演職員表的代碼快4-5倍。我認爲這是一個很好的理由來調查這一點,緩存是一個很好的代碼示例,可以從中受益。 – SeeR 2008-10-07 13:43:15

1

正如我發佈到Jon Skeet's blog,下面的方法可以幫助您避免劇組,如果這是一個擔心(雖然也許這會引入一些其他更嚴重的問題比鑄造:))。

如果你有一個微弱的字典實現(一個使用弱引用密鑰和淘未引用的鍵以及相關的值),你可以嘗試這樣的事:

public class TypeDictionary 
    {  
     private class InnerTypeDictionary<T> 
     { 
      static WeakDictionary<TypeDictionary, T> _innerDictionary = new WeakDictionary<TypeDictionary, T>(); 
      public static void Add(TypeDictionary dic, T value) 
      { 
       _innerDictionary.Add(dic, value); 
      } 

      public static T GetValue(TypeDictionary dic) 
      { 
       return _innerDictionary[dic]; 
      } 
     } 

     public void Add<T>(T value) 
     { 
      InnerTypeDictionary<T>.Add(this, value); 
     } 

     public T GetValue<T>() 
     { 
      return InnerTypeDictionary<T>.GetValue(this); 
     } 
    } 

它的好處將所有類型的查找變爲靜態泛型類型查找,而不直接求助於System.Type對象,所以我想這可能會給你一個性能上的提升。我很想知道它是否適合您的緩存場景。

0

我想我找到了解決方案。在這裏你可以實現ServiceProvider 你可以在my blog找到它的描述。

public class ServiceContainer : IDisposable 
{ 
    readonly IList<IService> services = new List<IService>(); 

    public void Add<T>(T service) 
    { 
     Add<T,T>(service); 
    } 

    public void Add<Key, T>(T service) where T : Key 
    { 
     services.Add(new Service<Key>(this, service)); 
    } 

    public void Dispose() 
    { 
     foreach(var service in services) 
      service.Remove(this); 
    } 

    ~ServiceContainer() 
    { 
     Dispose(); 
    } 

    public T Get<T>() 
    { 
     return Service<T>.Get(this); 
    } 
} 

public interface IService 
{ 
    void Remove(object parent); 
} 

public class Service<T> : IService 
{ 
    static readonly Dictionary<object, T> services = new Dictionary<object, T>(); 

    public Service(object parent, T service) 
    { 
     services.Add(parent, service); 
    } 

    public void Remove(object parent) 
    { 
     services.Remove(parent); 
    } 

    public static T Get(object parent) 
    { 
     return services[parent]; 
    } 
} 

是的,它使用靜態字段,但是所有引用都在終結刪除,因此唯一的缺點是保持的ServiceProvider一個GC一代比通常較長。

編輯:好的,經過幾次嘗試,我必須承認Jon Skeet是對的,目前沒有簡單的解決方案來解決這個問題。

  1. 我用Dictionary<WeakReference, T> services代替Dictionary<object, T> services
  2. 沒有服務將有參考的ServiceProvider:如果我履行2個約束我上面寫的解決方案才能發揮作用。

否則,你將有內存泄漏:-(

,微軟可以提供簡單的解決方案是創建本地的WeakReference < T>這將解決制約否2.我們可以這樣寫服務:

Dictionary<WeakReference, WeakReference<T>> services 
0

沒有好的方法來做到這一點,而不需要鑄造,不要掛在鑄造成本上,關注實際影響性能的東西......例如,哈希不是免費開始的。不應該在您每次使用時都回撥給您的服務提供商一項服務。一次獲得參考,您不必擔心檢索的安裝成本:

var service = provider.GetService<MyService>(); 
service.DoSomething(); 
service.DoSomethingElse();