2009-04-13 10 views
7

में कनवर्ट करना निम्नलिखित कोड को रूबी से सी # में परिवर्तित करने की आवश्यकता है। हालांकि मैं उपज कीवर्ड और रूबी के सामान्य वाक्यविन्यास के उपयोग से परेशान हूं। किसी को भी है कि एक छोटा सा रूबी जानता है कृपया मदद और कोड परिवर्तितरूबी को सी #

class < < Cache 
STALE_REFRESH = 1 
STALE_CREATED = 2 

# Caches data received from a block 
# 
# The difference between this method and usual Cache.get 
# is following: this method caches data and allows user 
# to re-generate data when it is expired w/o running 
# data generation code more than once so dog-pile effect 
# won't bring our servers down 
# 
def smart_get(key, ttl = nil, generation_time = 30.seconds) 
    # Fallback to default caching approach if no ttl given 
    return get(key) { yield } unless ttl 

    # Create window for data refresh 
    real_ttl = ttl + generation_time * 2 
    stale_key = "#{key}.stale" 

    # Try to get data from memcache 
    value = get(key) 
    stale = get(stale_key) 

    # If stale key has expired, it is time to re-generate our data 
    unless stale 
    put(stale_key, STALE_REFRESH, generation_time) # lock 
    value = nil # force data re-generation 
    end 

    # If no data retrieved or data re-generation forced, re-generate data and reset stale key 
    unless value 
    value = yield 
    put(key, value, real_ttl) 
    put(stale_key, STALE_CREATED, ttl) # unlock 
    end 

    return value 
end 

अंत

उत्तर

12

मुझे सी # बिल्कुल पता नहीं है, इसलिए सी # के बारे में जो कुछ भी मैं कहता हूं उसे नमक के अनाज से लिया जाना चाहिए। हालांकि, मैं यह समझाने की कोशिश करूंगा कि रुबी कोड के उस टुकड़े में क्या चल रहा है।

class << Cache 

रूबी कुछ सिंगलटन तरीकों कहा जाता है। इन्हें सिंगलटन सॉफ्टवेयर डिजाइन पैटर्न से कोई लेना देना नहीं है, वे केवल वे विधियां हैं जिन्हें एक और केवल एक ऑब्जेक्ट के लिए परिभाषित किया गया है। तो, आपके पास एक ही कक्षा के दो उदाहरण हो सकते हैं, और उन दो वस्तुओं में से एक में विधियां जोड़ सकते हैं।

सिंगलटन विधियों के लिए दो अलग-अलग वाक्यविन्यास हैं। एक ऑब्जेक्ट के साथ विधि के नाम को बस उपसर्ग करना है, इसलिए def foo.bar(baz) केवल foo ऑब्जेक्ट के लिए bar विधि को परिभाषित करेगा। दूसरी विधि को कहा जाता है जिसे सिंगलटन क्लास खोलना पड़ता है और यह कक्षा को परिभाषित करने के लिए वाक्य रचनात्मक रूप से समान दिखता है, क्योंकि यह भी अर्थात् होता है: सिंगलटन विधियां वास्तव में एक अदृश्य कक्षा में रहती हैं जो कक्षा में वस्तु और उसके वास्तविक वर्ग के बीच डाली जाती है पदानुक्रम।

यह वाक्यविन्यास इस तरह दिखता है: class << foo। यह ऑब्जेक्ट foo की सिंगलटन क्लास खोलता है और उस वर्ग निकाय के अंदर परिभाषित हर विधि ऑब्जेक्ट foo ऑब्जेक्ट की सिंगलटन विधि बन जाती है।

इसका उपयोग क्यों किया जाता है? खैर, रूबी एक शुद्ध ऑब्जेक्ट उन्मुख भाषा है, जिसका अर्थ है कि सब कुछ, कक्षाओं सहित एक वस्तु है। अब, यदि अलग-अलग वस्तुओं में विधियों को जोड़ा जा सकता है, और कक्षाएं वस्तुएं हैं, तो इसका मतलब है कि अलग-अलग वर्गों में विधियों को जोड़ा जा सकता है। दूसरे शब्दों में, रूबी को नियमित तरीकों और स्थैतिक तरीकों के बीच कृत्रिम भेद की आवश्यकता नहीं है (जो धोखाधड़ी है, वैसे भी: वे वास्तव में विधियां नहीं हैं, केवल गौरव प्रक्रियाएं हैं)। सी # में एक स्थिर विधि क्या है, क्लास ऑब्जेक्ट की सिंगलटन कक्षा पर केवल एक नियमित विधि है।

यह सब कुछ समझाने का एक लंबा तरीका है कि class << Cache और इसके संबंधित end के बीच परिभाषित सब कुछ static बन गया है।

STALE_REFRESH = 1 
    STALE_CREATED = 2 

रुबी में, प्रत्येक चर जो पूंजी पत्र से शुरू होता है, वास्तव में एक स्थिर है। हालांकि, इस मामले में हम इन्हें static const फ़ील्ड के रूप में अनुवाद नहीं करेंगे, बल्कि enum, क्योंकि इस तरह उनका उपयोग किया जाता है।

# Caches data received from a block 
    # 
    # The difference between this method and usual Cache.get 
    # is following: this method caches data and allows user 
    # to re-generate data when it is expired w/o running 
    # data generation code more than once so dog-pile effect 
    # won't bring our servers down 
    # 
    def smart_get(key, ttl = nil, generation_time = 30.seconds) 

इस विधि (वास्तव में चार, हम वास्तव में देखेंगे क्यों बाद में) तीन पैरामीटर है, उनमें से दो वैकल्पिक (ttl और generation_time) कर रहे हैं। उनमें से दोनों का डिफ़ॉल्ट मान है, हालांकि, ttl के मामले में डिफ़ॉल्ट मान वास्तव में उपयोग नहीं किया जाता है, यह यह जानने के लिए मार्कर के रूप में अधिक कार्य करता है कि तर्क पारित किया गया था या नहीं।

30.seconds एक विस्तार है कि ActiveSupport लाइब्रेरी Integer कक्षा में जोड़ती है। यह वास्तव में कुछ भी नहीं करता है, यह सिर्फ self देता है। इस मामले में विधि विधि परिभाषा को अधिक पठनीय बनाने के लिए प्रयोग किया जाता है। (अन्य विधियां हैं जो कुछ और उपयोगी बनाती हैं, उदाहरण के लिए Integer#minutes, जो self * 60 और Integer#hours और इसी तरह से लौटाती है।) हम इसे एक संकेत के रूप में उपयोग करेंगे, कि पैरामीटर का प्रकार int नहीं बल्कि System.TimeSpan होना चाहिए।

# Fallback to default caching approach if no ttl given 
    return get(key) { yield } unless ttl 

इसमें कई जटिल रूबी संरचनाएं हैं। आइए सबसे आसान से शुरू करें: पीछे सशर्त संशोधक। यदि एक सशर्त निकाय में केवल एक अभिव्यक्ति होती है, तो सशर्त अभिव्यक्ति के अंत में जोड़ा जा सकता है। तो, if a > b then foo end कहने के बजाय आप foo if a > b भी कह सकते हैं। तो, उपरोक्त unless ttl then return get(key) { yield } end के बराबर है।

अगला वाला भी आसान है: unlessif not के लिए सिंटैक्टिक चीनी है। तो, अब हम if not ttl then return get(key) { yield } end

तीसरे रूबी की सच्ची प्रणाली है। रूबी में, सच बहुत सरल है। दरअसल, झूठापन बहुत सरल है, और सच्चाई स्वाभाविक रूप से बाहर आती है: विशेष कीवर्ड false गलत है, और विशेष कीवर्ड nil गलत है, बाकी सब कुछ सच है। तो, इस मामले में सशर्त केवल सत्य हो, यदि ttl या तो false या nil है। false एक समय के लिए एक भयानक समझदार मूल्य नहीं है, इसलिए केवल दिलचस्प एक nil है। स्निपेट इस तरह अधिक स्पष्ट रूप से लिखा होगा: if ttl.nil? then return get(key) { yield } end। चूंकि ttl पैरामीटर के लिए डिफ़ॉल्ट मान nil है, इसलिए यह सशर्त सत्य है, यदि ttl के लिए कोई तर्क पारित नहीं हुआ है। इसलिए, सशर्त का उपयोग यह पता लगाने के लिए किया जाता है कि विधि को कितने तर्क कहा जाता था, जिसका अर्थ है कि हम इसे एक सशर्त के रूप में अनुवाद करने के लिए नहीं बल्कि एक विधि अधिभार के रूप में अनुवाद करने जा रहे हैं।

अब yield पर। रुबी में, प्रत्येक विधि एक निहित कोड ब्लॉक को तर्क के रूप में स्वीकार कर सकती है। यही कारण है कि मैंने ऊपर लिखा है कि विधि वास्तव में चार तर्क लेती है, तीन नहीं। एक कोड ब्लॉक कोड का एक अज्ञात टुकड़ा है जिसे चारों ओर पारित किया जा सकता है, एक चर में संग्रहीत किया जाता है, और बाद में इसका आह्वान किया जाता है। रुबी को स्मॉलटाक से ब्लॉक प्राप्त होते हैं, लेकिन अवधारणा लिस्प के लैम्ब्डा अभिव्यक्तियों के लिए 1 9 58 में सभी तरह से होती है। अज्ञात कोड ब्लॉक के उल्लेख पर, लेकिन कम से कम अब, लैम्ब्डा अभिव्यक्तियों के उल्लेख पर, आपको यह जानना चाहिए कि इस अंतर्निहित चौथे विधि पैरामीटर का प्रतिनिधित्व कैसे करें: एक प्रतिनिधि प्रकार, अधिक विशेष रूप से, Func

तो, yield क्या है? यह ब्लॉक पर नियंत्रण स्थानांतरित करता है। यह मूल रूप से एक चर को आमंत्रित करने के बिना एक ब्लॉक को आविष्कार करने का एक बहुत ही सुविधाजनक तरीका है और फिर इसे कॉल करना है।

# Create window for data refresh 
    real_ttl = ttl + generation_time * 2 
    stale_key = "#{key}.stale" 

यह #{foo} वाक्य रचना स्ट्रिंग प्रक्षेप कहा जाता है। इसका मतलब है "ब्रेसिज़ के बीच अभिव्यक्ति का मूल्यांकन करने के परिणामस्वरूप स्ट्रिंग के अंदर टोकन को प्रतिस्थापित करें"। यह String.Format() का एक बहुत ही संक्षिप्त संस्करण है, जो वास्तव में हम इसका अनुवाद करने जा रहे हैं।

# Try to get data from memcache 
    value = get(key) 
    stale = get(stale_key) 

    # If stale key has expired, it is time to re-generate our data 
    unless stale 
     put(stale_key, STALE_REFRESH, generation_time) # lock 
     value = nil # force data re-generation 
    end 

    # If no data retrieved or data re-generation forced, re-generate data and reset stale key 
    unless value 
     value = yield 
     put(key, value, real_ttl) 
     put(stale_key, STALE_CREATED, ttl) # unlock 
    end 

    return value 
    end 
end 

यह मेरी सी # करने के लिए रूबी संस्करण का अनुवाद पर कमजोर प्रयास है:

public class Cache<Tkey, Tvalue> { 
    enum Stale { Refresh, Created } 

    /* Caches data received from a delegate 
    * 
    * The difference between this method and usual Cache.get 
    * is following: this method caches data and allows user 
    * to re-generate data when it is expired w/o running 
    * data generation code more than once so dog-pile effect 
    * won't bring our servers down 
    */ 
    public static Tvalue SmartGet(Tkey key, TimeSpan ttl, TimeSpan generationTime, Func<Tvalue> strategy) 
    { 
     // Create window for data refresh 
     var realTtl = ttl + generationTime * 2; 
     var staleKey = String.Format("{0}stale", key); 

     // Try to get data from memcache 
     var value = Get(key); 
     var stale = Get(staleKey); 

     // If stale key has expired, it is time to re-generate our data 
     if (stale == null) 
     { 
      Put(staleKey, Stale.Refresh, generationTime); // lock 
      value = null; // force data re-generation 
     } 

     // If no data retrieved or data re-generation forced, re-generate data and reset stale key 
     if (value == null) 
     { 
      value = strategy(); 
      Put(key, value, realTtl); 
      Put(staleKey, Stale.Created, ttl) // unlock 
     } 

     return value; 
    } 

    // Fallback to default caching approach if no ttl given 
    public static Tvalue SmartGet(Tkey key, Func<Tvalue> strategy) => 
     Get(key, strategy); 

    // Simulate default argument for generationTime 
    // C# 4.0 has default arguments, so this wouldn't be needed. 
    public static Tvalue SmartGet(Tkey key, TimeSpan ttl, Func<Tvalue> strategy) => 
     SmartGet(key, ttl, new TimeSpan(0, 0, 30), strategy); 

    // Convenience overloads to allow calling it the same way as 
    // in Ruby, by just passing in the timespans as integers in 
    // seconds. 
    public static Tvalue SmartGet(Tkey key, int ttl, int generationTime, Func<Tvalue> strategy) => 
     SmartGet(key, new TimeSpan(0, 0, ttl), new TimeSpan(0, 0, generationTime), strategy); 

    public static Tvalue SmartGet(Tkey key, int ttl, Func<Tvalue> strategy) => 
     SmartGet(key, new TimeSpan(0, 0, ttl), strategy); 
} 

कृपया ध्यान दें कि मैं सी # पता नहीं है, मैं नेट पता नहीं है, मैं इस परीक्षण नहीं किया है, मैं यह भी नहीं पता कि यह वाक्य रचनात्मक रूप से वैध है या नहीं। उम्मीद है कि यह वैसे भी मदद करता है।

+0

@ जोर्ग - अगर आप रुबी से सी # रूपांतरण के लिए कोड पोस्ट करते हैं तो क्या आप मेरी मदद करेंगे ??? – maliks

+0

सही उत्तर: अच्छा स्पष्टीकरण + कोड – trinalbadger587

5

ऐसा प्रतीत होता है इस कोड को एक ब्लॉक पारित किया जा रहा है, तो कैश अनुरोध किया डेटा नहीं है मूल्यांकन किया जाना कर सकते हैं (yield यह है कि आप ब्लॉक को कैसे कॉल करते हैं)। यह काफी मूर्खतापूर्ण रूबी कोड है; मुझे नहीं पता कि कैसे (या यहां तक ​​कि अगर) आप इसे "अनुवाद" कर सकते हैं C#।

मेरा उपयोग करने के लिए एक केस देखने के लिए देखो। आप इस तरह अस्पष्ट कुछ खोजना चाहिए:

x = smart_get([:foo,"bar"]) { call_expensive_operation_foo("bar") } 

एक बेहतर शर्त यह पता लगाने की आप यह कर और कुछ है कि सी # में है कि नए सिरे से करता है, बल्कि गहरे लाल रंग का से "का अनुवाद" करने के लिए कोशिश कर रहा से लिखने की ज़रूरत क्या होगा।

+0

एक नेट> = 3.0 में लैम्ब्डा भाव के साथ कुछ इसी तरह (http://msdn.microsoft.com/en-us/library/bb397687.aspx देखें) कर सकता है। –

+0

आप एक भाषा से दूसरे भाषा में भारी बेवकूफ कोड का अनुवाद कर सकते हैं, साथ ही साथ आप कभी भी काम नहीं कर सकते। यह हमेशा जापानी दस्तक-दस्तक चुटकुले की तरह बदल जाता प्रतीत होता है। – MarkusQ

4

ऐसा लगता है कि आप रूबी से सी # तक पोर्ट मेमचेचे-क्लाइंट पोर्ट करने का प्रयास कर रहे हैं।

http://code.google.com/p/beitmemcached/

किसी भी तरह से, मैं आम तौर पर MarkusQ से सहमत एक उच्च स्तर की भाषा से एक निचले स्तर भाषा में अनुवाद है कि: यदि हां, तो यह इस तरह के रूप में एक देशी सी # मेम्कैश ग्राहक कार्यान्वयन उपयोग करने के लिए आसान हो सकता है शायद लक्ष्य भाषा के लिए एक बेवकूफ फैशन में फिर से लिखने की तुलना में कम उत्पादक होने जा रहा है। रुबी से सी # का सीधा अनुवाद आपको कुछ बहुत बदसूरत कोड देने जा रहा है।

उपज रूबी कीवर्ड आपको कोड के ब्लॉक को आमंत्रित करने की अनुमति देता है जो विधि के लिए एक निश्चित रूप से घोषित तर्क के रूप में पारित किया गया था। तो, उदाहरण के लिए, आप smart_get विधि परिभाषा के बारे में सोच सकते हैं के रूप में वास्तव में अधिक की तरह लग रही:

def smart_get(key, ttl = nil, generation_time = 30.seconds, &block) 

और जब आप इस तरह के रूप smart_get फोन:

x = smart_get("mykey", my_ttl) { do_some_operation_here } 

ब्रेसिज़ में सामान को सौंप दिया जाता है ऊपर विस्तारित परिभाषा में परिवर्तनीय ब्लॉक। उपज तब & ब्लॉक में कोड को आमंत्रित करती है। यह एक सकल सरलीकरण है, लेकिन आपको सामान्य विचार प्राप्त करने में मदद करनी चाहिए।

अपने रूपांतरण पर वापस जाएं। मैंने जो सरलीकरण किया है, वह आपको 100% प्राप्त करने के लिए जरूरी नहीं है, क्योंकि जैसे ही आपको उस कोड का अनुवाद करने के लिए सी # तरीका मिल जाए, कोड का एक और टुकड़ा आपके अनुवाद को तोड़ देगा।

foo = lambda { |a, b, c| a + b + c } 
# foo is now defined as a function that sums its three arguments 

और:

def foo 
    if block.arity == 0 
     # No arguments passed, load defaults from config file and ignore call 
    else 
     yield 
    end 
end 

और lambdas के बाद निश्चित रूप से रूबी में प्रथम श्रेणी वस्तुओं रहे हैं, तो आपको निम्न की तरह कोड का सामना कर सकते: उदाहरण के लिए, मान लीजिए कि किसी दिए गए विधि ब्लॉक का निरीक्षण करने की जरूरत है चलो यदि आप कोड है कि मक्खी, या (एक अनुवादक के लिए बदतर) पर विधियां निर्धारित मुठभेड़ तो भगवान आपकी मदद कर रूबी के लचीला वर्गों के लाभ लेता है:

class Foo 
    def show 
     puts "Foo" 
    end 
end 

foo = Foo.new 
foo.show # prints "Foo" 

class <&lt;foo; def show; puts "Bar"; end; end 

foo.show # prints "Bar" 

Foo.new.show # prints "Foo" 

foo.show # Still prints "Bar" 

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

0

इस प्रयास करें:

def foo 
    if block.arity == 0 
     # No arguments passed, load defaults from config file and ignore call 
    else 
     yield 
    end 
end