yield关键字来消化像Ruby这样的代码块

时间:2013-09-29 07:16:15

标签: c# .net syntax

在Ruby中,我们可以从其他范围产生代码块,以优化编写代码的数量:

  def get_resource(published=true)
    find_resources do
      if I18n.locale == :ar && @resource_slug == "home"
        Resource.find_by_slug("home")
      else
        ResourceType.find_by_slug(@type_slug).resources.send(
          published ? :published : :unpublished
        ).find_by_slug(@resource_slug)
      end
    end
  end

  def get_resources(published=true)
    find_resources do
      ResourceType.includes(:resources).find_by_slug(@type_slug).resources.send(
        published ? :published : :unpublished
      )
    end
  end

  def find_resources
    begin
      @type_slug, @resource_slug = params[:type], params[:resource]
      yield
    rescue Mongoid::Errors::DocumentNotFound, NoMethodError
      nil
    end
  end

在C#中,我们还有yield关键字。以下是示例taken from documentation

//using System.Collections;  
//using System.Diagnostics; 
public static void Process()
{
    // Display powers of 2 up to the exponent of 8:  
    foreach (int number in Power(2, 8))
    {
        Debug.Write(number.ToString() + " ");
    }
    // Output: 2 4 8 16 32 64 128 256
}


public static IEnumerable Power(int baseNumber, int highExponent)
{
    int result = 1;

    for (int counter = 1; counter <= highExponent; counter++)
    {
        result = result * baseNumber;
        yield return result;
    }
}

C#yield似乎是从迭代方法返回中间结果的方法,而不是Ruby在运行时将整个代码块压缩到指定区域的方式。

是否有类似的技术使用yield关键字在C#中编写更少的代码?例如:

public class EntityBase 
{

   // Generic Try-Catch function, so we never have to write this block in our code

   public object GenericTryCatch()
    {
        try
        {
            // yield here
        }
        catch(Exception except)
        {
            Logger.log(except.Message);
        }
        finally
        {
            // return the control to the caller function
        }

        return null;

    }
}

2 个答案:

答案 0 :(得分:4)

我不知道Ruby,但看起来基本上你想要传递“一些代码来执行” - 这通常是在C#中使用委托(或接口,当然是特定含义)来完成的。据我所知,Ruby中的yield与C#中的yield return完全不同。如果您没有任何参数或返回值,则Action委托是合适的。然后,您可以使用任何方法调用该方法来创建委托,例如:

  • 现有方法,通过方法组转换或显式委托创建表达式
  • 一个lambda表达式
  • 匿名方法

例如:

Foo(() => Console.WriteLine("Called!"));

...


static void Foo(Action action)
{
    Console.WriteLine("In Foo");
    action();
    Console.WriteLine("In Foo again");
    action();
}

有很多关于代表的知识 - 不幸的是,我现在没有时间详细介绍它们,但我建议你找一本关于C#的好书并从中了解它们。 (特别是,它们可以接受参数和返回值这一事实在各种情况下都很重要,包括LINQ。)

答案 1 :(得分:4)

我对Ruby的有限知识告诉我你只想要某种代表:

void SomeMethod(Action action) {
    // do some stuff here
    action(); // the equivalent (that I can see) of yield
}

用法:

SomeMethod(() => {
    // method that is called when execution hits "action()" above
});