将数组序列 T myArray[] 转换为 IEnumerable在 c# 中

发布于 2024-10-19 21:44:16 字数 546 浏览 8 评论 0原文

在下面的代码中,我想返回 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;
   }
}

In the following code I want to return an IEnumerable without creating a new data structure object. However, I get a compiler error with the following code. What am I missing?

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

ぃ弥猫深巷。 2024-10-26 21:44:16

Type.GetFields 返回 FieldInfo 对象的数组。

由于您没有返回数组的集合,因此您必须迭代该数组并返回其中的每个对象,有点像这样:

foreach (var fi in objectType.GetFields(...))
    yield return fi;

Type.GetFields returns an array of FieldInfo objects.

Since you´re not returning a collection of arrays, you have to iterate over the array and yield return each object in it, kinda like this:

foreach (var fi in objectType.GetFields(...))
    yield return fi;
浅浅淡淡 2024-10-26 21:44:16

yield return 对单个元素进行操作;您只需返回GetFields的返回值即可达到您想要的效果。

进一步解释一下,当您想要在将序列中的每个项目提供给调用者使用之前对其应用某些操作,但您又不想执行所有操作时,yield return 主要有用预先工作并简单地以数组或 List 形式返回聚合结果。

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

编辑:抱歉 - 我错过了您的代码的要点之一(枚举基本字段),但我会保留这个答案,因为我认为它无论如何都可能有用。 Lasse Karlsen 的答案将满足您的需要,但除非您有一个巨大的类型层次结构,否则与仅聚合结果并将它们返回到数组相比,您并没有真正获得任何优势。

yield return operates on single elements; you can simply return the return value from GetFields to achieve what you want.

To explain further, yield return is mainly useful when you want to apply some operation to each item in a sequence before making it available to the caller, but you don't want to do all of that work up-front and simply return the aggregate results in an array or List<T>.

yield return makes this deferred execution easy to write, because the generated iterator block only applies any such operation to each item as it's requested.

EDIT: Sorry - I missed one of the points of your code (enumerating the base fields), but I'll leave this answer up since I think it might be useful anyway. Lasse Karlsen's answer will do what you need, but unless you have a huge type hierarchy, you're not really gaining any advantage over just aggregating the results and returning them in an array.

浊酒尽余欢 2024-10-26 21:44:16

您可以尝试递归+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));
}

You can try recursion + 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));
}
魂ガ小子 2024-10-26 21:44:16

您正在寻找的是“所有人的收益”。您必须遍历并产生返回从 GetFields 返回的每个项目,然后设置为基类。

但这不是必需的,因为有一个标志指示是否包含基类定义。

What you're looking for is a "yield forall." You'd have to foreach through and yield return each item returned from GetFields and then set to the base class.

This shouldn't be necessary though because there is a flag for whether or not to include base-class definitions.

满身野味 2024-10-26 21:44:16

稍微递归一下怎么样?

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));
 }

How about a little recursion?

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));
 }
旧时光的容颜 2024-10-26 21:44:16

正如大家所指出的,问题在于生成的元素的类型与预期的类型不匹配。

为了避免每次都编写 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;
}

As everybody pointed out, the issue is that the type of the element yielded doesn't match with the type expected.

To avoid writing a for/while/foreach every time, I like to use an extension method that handles the iteration for me.

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

That way, you can return the fields writing a much more readable query

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;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文