在下面的代码中,我希望在不创建新数据结构对象的情况下返回IEnumerable。但是,我使用以下代码得到编译器错误。我错过了什么?
Error Cannot implicitly convert type 'System.Reflection.FieldInfo[]' to 'System.Reflection.FieldInfo'
public static IEnumerable<FieldInfo> GetAllFields(Type objectType)
{
while (objectType != null)
{
//GetFields(...) returns a FieldInfo []
yield return objectType.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
objectType = objectType.BaseType;
}
}
答案 0 :(得分:4)
yield return
针对单个元素进行操作;您只需返回GetFields
的返回值即可实现您的目标。
为了进一步解释,yield return
主要用于在将一些操作应用于序列中的每个项目之后才能使其对调用者可用,但是您不希望完成所有这些操作预先工作并简单地将聚合结果返回到数组或List<T>
。
yield return
使延迟执行易于编写,因为生成的迭代器块仅对请求的每个项目应用任何此类操作。
答案 1 :(得分:4)
Type.GetFields返回一个FieldInfo对象数组。
由于你没有返回一个数组集合,你必须迭代数组并返回其中的每个对象,有点像这样:
foreach (var fi in objectType.GetFields(...))
yield return fi;
答案 2 :(得分:1)
您可以尝试递归+ Concat
:
public static IEnumerable<FieldInfo> GetAllFields(Type objectType)
{
if (objectType == null)
return Enumerable<FieldInfo>.Empty;
else
return objectType.GetFields(
BindingFlags.NonPublic | BindingFlags.Public |
BindingFlags.Instance | BindingFlags.DeclaredOnly)
.Concat(GetAllFields(objectType.BaseType));
}
答案 3 :(得分:0)
您正在寻找的是“收益率”。您必须预先通过并返回从GetFields返回的每个项目,然后设置为基类。
这不应该是必要的,因为有一个标志是否包含基类定义。
答案 4 :(得分:0)
一点点递归怎么样?
public static IEnumerable<FieldInfo> GetAllFields(Type objectType)
{
//GetFields(...) returns a FieldInfo []
var fields = objectType.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
if(objectType.BaseType==null) return fields;
return fields.Concat(GetAllFields(object.BaseType));
}
答案 5 :(得分:0)
正如大家所指出的那样,问题是产生的元素类型与预期的类型不匹配。
为了避免每次都写一个for / while / foreach,我喜欢使用一个为我处理迭代的扩展方法。
public static class Sequence
{
public static IEnumerable<T> Create<T>(T seed, Func<T, bool> predicate, Func<T, T> next)
{
for (T t = seed; predicate(t); t = next(t))
yield return t;
}
}
这样,您可以返回编写更易读的查询的字段
public static IEnumerable<FieldInfo> GetAllFields(Type objectType)
{
BindingFlags flags = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly;
return from type in Sequence.Create(objectType, t => t != null, t => t.BaseType)
from field in type.GetFields(flags)
select field;
}