2009-09-10 9 views
5

मैं जेनिक्स का उपयोग कर identity map को लागू करने की कोशिश कर रहा हूं। मेरे पास एक अमूर्त वर्ग, संस्था, और संस्था के लिए मेरे मानचित्र पर एक व्युत्पन्न बाधा है। चूंकि मेरे मानचित्र को संस्थाओं को तुरंत चालू करने में सक्षम होना आवश्यक है, इसलिए मेरे मानचित्र में एक कन्स्ट्रक्टर बाधा भी है।सी # में जेनेरिक पहचान मानचित्र। सार्वजनिक कन्स्ट्रक्टर नहीं चाहते हैं

हालांकि, मानचित्र के लिए उपयोगी होने के लिए, इकाई सबक्लास को क्लाइंट कोड से तत्काल नहीं किया जाना चाहिए, जिसका अर्थ है कि मैं एक आंतरिक कन्स्ट्रक्टर और कोई सार्वजनिक निर्माता नहीं चाहता हूं। हालांकि, यह कन्स्ट्रक्टर बाधा के साथ संघर्ष करता है।

क्या मुझे कुछ याद आ रही है? वांछित परिणाम प्राप्त करने के लिए इसे पुन: सक्रिय करने का कोई तरीका है?

निम्न कोड को संकलित करता है के रूप में है, लेकिन, आदर्श, एंटिटी के उपवर्गों 'कंस्ट्रक्टर्स आंतरिक होगा:

public abstract class Entity 
{ 
    public int Id { get; protected internal set; } 
} 

public sealed class Widget : Entity 
{ 
    // Client code should not be allowed to instantiate entities. 
    // But the constraints on EntityMap require that entities have 
    // a public constructor. 
    public Widget() { } 
} 

public sealed class Gadget : Entity 
{ 
    public Gadget() { } 
} 

// The new() constraint is required so that Get() can instantiate Ts. 
public class EntityMap<T> where T : Entity, new() 
{ 
    private Dictionary<int, T> _entities = new Dictionary<int, T>(); 
    private object _getLock = new object(); 

    public T Get(int id) 
    { 
     lock (_getLock) 
     { 
      if (!_entities.ContainsKey(id)) 
       _entities.Add(id, new T() { Id = id }); 
     } 

     return _entities[id]; 
    } 

    // Client code should not be allowed to instantiate maps. 
    internal EntityMap() { } 
} 

// Ideally, the client would only be able to obtain Entity 
// references through EntityMaps, which are only accessible 
// through the ApplicationMap. 
public static class ApplicationMap 
{ 
    public static EntityMap<Widget> Widgets = new EntityMap<Widget>(); 
    public static EntityMap<Gadget> Gadgets = new EntityMap<Gadget>(); 
} 

उत्तर

9

इसके बजाय एक निर्माता बाधा की आवश्यकता होती है, नक्शे निर्माता के लिए एक Func<T> गुजरती हैं। इस तरह निर्माता आंतरिक हो सकता है, लेकिन नक्शे अभी भी प्रभावी रूप से यह कॉल कर सकते हैं: फिर

public class EntityMap<T> where T : Entity 
{ 
    private readonly Dictionary<int, T> _entities = new Dictionary<int, T>(); 
    private readonly object _getLock = new object(); 
    private readonly Func<T> _entityGenerator; 

    public T Get(int id) 
    { 
     lock (_getLock) 
     { 
      T ret; 
      if (!_entities.TryGetValue(id, ret)) 
      { 
       ret = entityGenerator(); 
       newEntity[id] = ret; 
       ret.Id = id; 
      } 

      return ret; 
     } 
    } 

    internal EntityMap(Func<T> entityGenerator) 
    { 
     _entityGenerator = entityGenerator; 
    } 
} 

के साथ प्रारंभ:

EntityMap<Widget> widgetMap = new EntityMap(() => new Widget()); 

आप संभवतः यह एक Func<int, T> बजाय कर सकता है और के लिए प्रतिनिधि जिम्मेदार बनाना सही आईडी के साथ एक इकाई बनाना। इस तरह आप Entity कन्स्ट्रक्टर के पैरामीटर के रूप में इसे ले जाने के लिए अपना आईडी ठीक से पढ़ सकते हैं।

(। मैं अपने Get विधि अधिक कुशल, btw बनाने की स्वतंत्रता लिया है)

+0

क्या बजाय TryGetValue उपयोग करने का लाभ है ContainsKey? क्या यह गति का मुद्दा है? – Lobstrosity

2

जॉन के लिए धन्यवाद, यहाँ काम कर कोड है:

public abstract class Entity 
{ 
    private readonly int _id; 

    public int Id 
    { 
     get { return _id; } 
    } 

    internal Entity(int id) 
    { 
     _id = id; 
    } 
} 

public sealed class Widget : Entity 
{ 
    internal Widget(int id) : base(id) { } 
} 

public sealed class Gadget : Entity 
{ 
    internal Gadget(int id) : base(id) { } 
} 

public class EntityMap<T> where T : Entity 
{ 
    private readonly Dictionary<int, T> _entities = new Dictionary<int, T>(); 
    private readonly object _getLock = new object(); 
    private readonly Func<int, T> _entityGenerator; 

    public T Get(int id) 
    { 
     lock (_getLock) 
     { 
      T entity; 

      if (!_entities.TryGetValue(id, out entity)) 
       _entities[id] = entity = _entityGenerator(id); 

      return entity; 
     } 
    } 

    internal EntityMap(Func<int, T> entityGenerator) 
    { 
     _entityGenerator = entityGenerator; 
    } 
} 

public static class ApplicationMap 
{ 
    public static readonly EntityMap<Widget> Widgets = new EntityMap<Widget>(id => new Widget(id)); 
    public static readonly EntityMap<Gadget> Gadgets = new EntityMap<Gadget>(id => new Gadget(id)); 
} 
+1

आप इसे वैकल्पिक उत्तर के बजाय अपनी मूल पोस्ट में संपादित करने के लिए बेहतर पोस्ट करेंगे। – jpierson

संबंधित मुद्दे