2012-01-12 14 views
6

मैं एक क्लास लाइब्रेरी तैयार कर रहा हूं जिसमें "EnsureXXX" की विधि का एक समूह है। इस विधियों का विचार तब भी कहा जाना चाहिए जब किसी कॉलिंग कोड को कुछ की आवश्यकता हो, जिसके लिए तर्कों के लिए प्रारंभिक प्रारंभिक आवश्यकता हो। यह ASP.Net की EnsureChildControls विधि जैसा है, लेकिन भेदभावकर्ताओं के रूप में तर्क के साथ।यह सुनिश्चित करने के लिए कि एक तर्क तर्क प्रति तर्क संयोजन केवल एक बार निष्पादित किया जाता है?

पूर्व:

public static class SomeUtilityClass { 
    public static void EnsureSomething(string arg1, int arg2, object arg3) 
    { 
     // Logic should be called once for each args combination 
    } 
} 

public class CallerClass 
{ 
    public void Foo() 
    { 
     SomeUtilityClass.EnsureSomething("mycustomerid", 4, myData.SomeProperty); 
    } 
    public void Foo2() 
    { 
     SomeUtilityClass.EnsureSomething("mycustomerid", 4, myData.SomeProperty); 
    } 

} 

के रूप में इस तरह के पैटर्न कई जगहों पर पुन: उपयोग किया जाएगा और बहुत बार कहा जाता है, मैं एक लक्ष्य के रूप प्रदर्शन रखना है। मुझे थ्रेड-सुरक्षित विधि भी होनी चाहिए।

public sealed class CallHelper 
{ 
    private static readonly HashSet<int> g_YetCalled = new HashSet<int>(); 
    private static readonly object g_SyncRoot = new object(); 

    public static void EnsureOnce(Type type, Action a, params object[] arguments) 
    { 
     // algorithm for hashing adapted from http://stackoverflow.com/a/263416/588868 
     int hash = 17; 
     hash = hash * 41 + type.GetHashCode(); 
     hash = hash * 41 + a.GetHashCode(); 
     for (int i = 0; i < arguments.Length; i++) 
     { 
      hash = hash * 41 + (arguments[i] ?? 0).GetHashCode(); 
     } 

     if (!g_YetCalled.Contains(hash)) 
     { 
      lock (g_SyncRoot) 
      { 
       if (!g_YetCalled.Contains(hash)) 
       { 
        a(); 
        g_YetCalled.Add(hash); 
       } 
      } 
     } 
    } 
} 

लेने वाली कोड इस तरह दिखता है:

public static class Program 
{ 
    static void Main() 
    { 
     SomeMethod("1", 1, 1); 
     SomeMethod("2", 1, 1); 
     SomeMethod("1", 1, 1); 
     SomeMethod("1", 1, null); 

     Console.ReadLine(); 
    } 

    static void SomeMethod(string arg1, int arg2, object arg3) 
    { 
     CallHelper.EnsureOnce(typeof(Program),()=> 
     { 
      Console.WriteLine("SomeMethod called only once for {0}, {1} and {2}", arg1, arg2, arg3); 
     }, arg1, arg2, arg3); 
    } 
} 

उत्पादन किया जाता है, के रूप में की उम्मीद:

SomeMethod called only once for 1, 1 and 1 
SomeMethod called only once for 2, 1 and 1 
SomeMethod called only once for 1, 1 and 

इस प्रयोजन के लिए, मैं एक छोटे उपयोगिता वर्ग लिखा था मेरे पास इस दृष्टिकोण से संबंधित कुछ प्रश्न हैं:

  1. मुझे लगता है कि मैंने थ्रेड सुरक्षा सुनिश्चित करने के लिए कक्षा को ठीक से लॉक कर दिया है, लेकिन क्या मैं सही हूँ?
  2. HashSet<int> है और हैश की गणना करने की मेरी पद्धति सही है? मैं विशेष रूप से सोच रहा हूं कि null हैंडलिंग सही है, और यदि मैं Action इस तरह से "हैश" कर सकता हूं।
  3. मेरी विधियां वर्तमान में केवल स्थिर विधियों का समर्थन करती हैं। मेमोरी लीकिंग के बिना मैं एक उदाहरण संगत विधि (उदाहरण को भेदभावकर्ता के रूप में जोड़ना) में कैसे जा सकता हूं?
  4. क्या स्टैक्र्रेस (प्रदर्शन प्रभाव की वजह से) की खोज किए बिना उपयोगिता विधि (केवल कार्रवाई निर्दिष्ट करना) के लिए मैन्युअल रूप से सभी तर्कों को पार करने से बचने का कोई तरीका है? मुझे डर है कि बाहरी विधि से लापता तर्कों के कारण बहुत सारी बग पेश की गई हैं।

अग्रिम धन्यवाद

+1

यह "सुनिश्चित करें" तकनीक को ज्ञापन कहा जाता है - यदि आप इसकी खोज करते हैं तो आपको Google पर बहुत सारी चीज़ें मिलेंगी। –

उत्तर

5

में यह अनिवार्य रूप से एक memoize है, सिवाय अपने कार्य शून्य है। लेकिन इनपुट तर्कों की तुलना के लिए एक ही विचार अभी भी वैध हैं।

वेस डायर how to make a generic, multi-argument memoize in this post पर चर्चा करता है। सामान्य विचार सभी तर्कों को एक अनाम प्रकार में रोल करना है, और इसे कुंजीपटल कुंजी के रूप में उपयोग करना है।

इस थ्रेड-सुरक्षित बनाने के संबंध में, .NET already has concurrent collections पर विचार करें। आपको समवर्ती एक गैर-समवर्ती संग्रह बनाने की आवश्यकता नहीं है; बस प्रदान किए गए संग्रह का उपयोग करें।

इस काम को उदाहरण के तरीकों के लिए लीक किए बिना बनाने के लिए, या तो WeakReference को उदाहरण के लिए रखें या उदाहरण के लिए मेमोइज़र का एक उदाहरण स्टोर करें, जो भी आपके लिए काम करता है।

+0

वेस डायर की प्रविष्टि वही है जो मैं ढूंढ रहा था। मुझे नहीं पता था कि इसे ज्ञापन कहा जाता था। धन्यवाद –

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