在C#中是否可以通过反射检查方法是否为迭代器?

时间:2020-01-17 08:40:14

标签: c# reflection iterator yield yield-return

给出一个MethodBaseMethodInfo实例,如何检查它代表的是迭代器方法(带有yield语句)还是普通方法(没有yield语句) ?

我注意到IteratorStateMachineAttribute属性中有一个CustomAttributes,但是here提到应该依赖此属性。

1 个答案:

答案 0 :(得分:0)

否,这是不可能的-由于yield是编译器在编译过程中正在处理的上下文关键字,因此您无法直接对其进行检查(请参阅yield contectual keyword)-您可以找到{{ 3}}是C#语言提供的连续关键字的列表。

定义

上下文关键字(例如 yield )用于在代码中提供特定的含义,但在C#中不是保留字。某些上下文关键字,例如 partial where ,在两个或多个上下文中具有特殊含义。

您可以找到类似的解释here,为什么不能通过反射轻松找到它。

但是我认为检查IEnumerable就足够了-因为此接口保证了Iterator可用(请参见here)。请考虑以下方法:

IEnumerable<int> Iterator()
{
    for (int i = 0; i < 10; i++)
    {
        yield return i;
    };
}

一种检查是否可以进行迭代的方法是:

if (Iterator() is IEnumerable)
    foreach (var item in Iterator())
    {
        Debug.WriteLine(item.ToString());
    }
else
    Debug.WriteLine("Cannot iterate!");

另一种方法是通过泛型进行声明:

void Iterate<T>(T iterator)
    where T: System.Collections.IEnumerable
{
    foreach (var item in iterator)
    {
        Debug.WriteLine(item.ToString());
    }
}

您可以通过以下方式调用它:

Iterate(Iterator());

区别在于,通过泛型,编译器将在应用程序运行之前 对其进行检查并给出编译错误,而第一个示例在运行时 对其进行检查,即它将编译但在运行时失败。

当然,您也可以遍历数组,这很好用(请参见下面由iterators添加的注释):

var intArray = new int[] {1,2,3};
Iterate(intArray);

您还可以显式检查枚举数,即

void Iterate2<T>(T collection)
where T: IEnumerable
{
    var enumerator = collection.GetEnumerator();
    if (enumerator is IEnumerator)
        while (enumerator.MoveNext())
        {
            var item = enumerator.Current;
            Console.WriteLine(item.ToString());
        }
}

我把这些例子放在一起 CodeCaster 因此您可以立即尝试。

相关问题