在c#</t>中将一系列数组T myArray []转换为IEnumerable <t>

时间:2011-02-28 20:08:22

标签: c# linq enumerable

在下面的代码中,我希望在不创建新数据结构对象的情况下返回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;
   }
}

6 个答案:

答案 0 :(得分:4)

yield return针对单个元素进行操作;您只需返回GetFields的返回值即可实现您的目标。

为了进一步解释,yield return主要用于在将一些操作应用于序列中的每个项目之后才能使其对调用者可用,但是您不希望完成所有这些操作预先工作并简单地将聚合结果返回到数组或List<T>

yield return使延迟执行易于编写,因为生成的迭代器块仅对请求的每个项目应用任何此类操作。

编辑:对不起 - 我错过了你的代码中的一个要点(枚举基本字段),但我会留下这个答案,因为我认为它可能有用。 Lasse Karlsen的答案将满足您的需求,但除非您拥有庞大的类型层次结构,否则您只是在聚合结果并将其返回到数组中时,并没有获得任何优势。

答案 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;
}