gpt4 book ai didi

c# - 将 Ruby 转换为 C#

转载 作者:数据小太阳 更新时间:2023-10-29 06:55:57 24 4
gpt4 key购买 nike

需要将以下代码从 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

结尾

最佳答案

我根本不懂 C#,所以我对 C# 说的任何话都应该持保留态度。但是,我将尝试解释这段 Ruby 代码中发生的事情。

class << Cache

Ruby 有一种叫做单例方法的东西。这些与单例软件设计模式无关,它们只是为一个且仅一个对象定义的方法。因此,您可以拥有同一个类的两个实例,并向这两个对象之一添加方法。

单例方法有两种不同的语法。一种是在方法名前加上对象,所以 def foo.bar(baz)将定义一个方法 bar仅适用于对象 foo .另一种方法称为打开单例类,它在语法上看起来类似于定义一个类,因为这也是语义上发生的事情:单例方法实际上存在于一个不可见的类中,该类插入到对象与其在类层次结构中的实际类之间。

此语法如下所示: class << foo .这将打开对象的单例类 foo并且在该类体内定义的每个方法都成为对象 foo 的单例方法.

为什么在这里使用它?嗯,Ruby 是一种纯面向对象的语言,这意味着一切,包括类,都是一个对象。现在,如果方法可以添加到单个对象中,而类就是对象,这意味着可以将方法添加到单个类中。换句话说,Ruby 不需要人为区分常规方法和静态方法(无论如何,这是一种欺诈:它们不是真正的方法,只是美化的过程)。什么是 C# 中的静态方法,只是类对象的单例类上的常规方法。

所有这些只是一种冗长的方式来解释 class << Cache 之间定义的所有内容。及其对应的 end变成 static .
  STALE_REFRESH = 1
STALE_CREATED = 2

在 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)

这个方法有三个参数(实际上是四个,我们稍后会看到确切原因),其中两个是可选的( ttlgeneration_time )。但是,在 ttl 的情况下,它们都有一个默认值。默认值并没有真正使用,它更多地作为一个标记来确定参数是否被传入。
30.secondsActiveSupport 的扩展名库添加到 Integer类(class)。它实际上什么都不做,它只是返回 self .在这种情况下使用它只是为了使方法定义更具可读性。 (还有其他方法可以做一些更有用的事情,例如 Integer#minutes ,它返回 self * 60Integer#hours 等等。)我们将使用它作为指示,参数的类型不应该是 int而是 System.TimeSpan .
    # Fallback to default caching approach if no ttl given
return get(key) { yield } unless ttl

这包含几个复杂的 Ruby 结构。让我们从最简单的开始:尾随条件修饰符。如果条件体仅包含一个表达式,则可以将条件附加到表达式的末尾。所以,而不是说 if a > b then foo end你也可以说 foo if a > b .所以,以上等价于 unless ttl then return get(key) { yield } end .

下一个也很简单: unless只是 if not 的语法糖.所以,我们现在在 if not ttl then return get(key) { yield } end
第三是Ruby的真值系统。在 Ruby 中,真相非常简单。其实,假很简单,真自然就出来了:特殊关键字 false为假,特殊关键字 nil是假的,其他都是真的。所以,在这种情况下,条件只有在 ttl 时才为真。要么是 falsenil . false对于时间跨度来说并不是一个糟糕的合理值,所以唯一有趣的是 nil .这段代码应该更清楚地写成这样: if ttl.nil? then return get(key) { yield } end .由于 ttl 的默认值参数为 nil ,如果没有为 ttl 传入参数,则此条件为真.因此,条件用于计算调用了多少个参数,这意味着我们不会将其转换为条件,而是将其转换为方法重载。

现在,转到 yield .在 Ruby 中,每个方法都可以接受一个隐式代码块作为参数。这就是为什么我在上面写到该方法实际上需要四个参数,而不是三个。代码块只是一段匿名代码,可以传递、存储在变量中并在以后调用。 Ruby 从 Smalltalk 继承了块,但这个概念可以追溯到 1958 年,Lisp 的 lambda 表达式。在提到匿名代码块时,但至少现在,在提到 lambda 表达式时,您应该知道如何表示这个隐式的第四个方法参数:委托(delegate)类型,更具体地说,是 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

这是我将 Ruby 版本转换为 C# 的微弱尝试:
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);
}

请注意,我不知道 C#,我不知道 .NET,我没有测试过这个,我什至不知道它在语法上是否有效。希望它无论如何都有帮助。

关于c# - 将 Ruby 转换为 C#,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/744620/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com