Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/267.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
将Ruby转换为C#_C#_Ruby_Caching - Fatal编程技术网

将Ruby转换为C#

将Ruby转换为C#,c#,ruby,caching,C#,Ruby,Caching,需要将以下代码从Ruby转换为C#。然而,我对使用yield关键字和Ruby的一般语法感到困惑。任何懂一点Ruby的人都可以帮忙转换代码吗 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 metho

需要将以下代码从Ruby转换为C#。然而,我对使用yield关键字和Ruby的一般语法感到困惑。任何懂一点Ruby的人都可以帮忙转换代码吗

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
class<

结束

如果缓存中不包含请求的数据,则此代码似乎正在传递一个要评估的块(
yield
是对该块的调用方式)。这是相当地道的ruby代码;我不知道你如何(甚至是否)把它“翻译”成c

寻找一个用例来了解我的意思。你会发现一些模糊的东西,比如:

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

更好的办法是找出需要它做什么,并用c#编写一些从头开始的东西,而不是尝试从ruby“翻译”。

看起来您正在尝试将memcache客户端从ruby移植到c#。如果是这样,使用本机C#memcache客户端实现可能更容易,例如:

不管是哪种方式,我大体上同意MarkusQ的观点,即从高级语言到低级语言的翻译,总的来说可能会比仅仅用目标语言的惯用方式重写效率更低。从Ruby到C的直接转换最多会给您一些非常难看的代码

yield Ruby关键字允许调用作为隐式声明参数传递给方法的代码块。例如,您可以认为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 }
大括号中的内容将分配给上面扩展定义中的变量块。然后,yield调用&block中的代码。这是一个粗略的简化,但应该有助于您了解总体思路

回到你的转换。我刚才所做的简化并不一定能让你100%地理解,因为一旦你找到一种C#方式来翻译代码,另一段代码就会打断你的翻译。例如,假设给定的方法需要检查块:

def foo
   if block.arity == 0
      # No arguments passed, load defaults from config file and ignore call
   else
      yield
   end
end
当然,由于lambda是Ruby中的一流对象,因此您可能会遇到如下代码:

foo = lambda { |a, b, c| a + b + c }   
# foo is now defined as a function that sums its three arguments
如果您遇到定义动态方法的代码,或者(更糟糕的是,对于翻译器)利用Ruby的可扩展类,那么上帝会帮助您:

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"
class-Foo
def秀
放“福”
结束
结束
foo=foo.new
foo.show#打印“foo”
同学们我一点也不懂C,所以我所说的关于C的任何话都应该被全盘接受。然而,我将尝试解释这段Ruby代码中发生了什么

class << Cache
在Ruby中,每个以大写字母开头的变量实际上都是常量。但是,在本例中,我们不会将这些转换为
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\u 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
这包含几个复杂的Ruby构造。让我们从最简单的一个开始:尾部条件修饰符。如果条件体仅包含一个表达式,则可以将该条件附加到表达式的末尾。因此,与其说
如果a>b那么foo end
,不如说
foo如果a>b
。因此,除非ttl然后返回get(key){yield}end
,否则上述操作相当于

下一个问题也很简单:
,除非
只是
的语法糖,如果不是
。因此,我们现在在
如果不是ttl,那么返回get(key){yield}end

第三是鲁比的真理体系。在Ruby中,真相非常简单。事实上,谬误很简单,真理自然就会显现出来:特殊关键字
false
是假的,特殊关键字
nil
是假的,其他一切都是真的。因此,在这种情况下,只有当
ttl
false
nil
时,条件才会为true
false对于时间跨度来说不是一个非常合理的值,因此唯一有趣的值是
nil    # 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
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);
}
def foo
   if block.arity == 0
      # No arguments passed, load defaults from config file and ignore call
   else
      yield
   end
end