【问题标题】:Yield return and dynamic收益率和动态
【发布时间】:2014-03-21 21:01:16
【问题描述】:

使用动态时是否可以调用“IEnumerable/yield return”方法?

我之所以这么问,是因为当我调用“Test(States1.GetNames())”方法时出现以下错误。

错误:“附加信息:‘object’不包含‘GetEnumerator’的定义”

using System;
using System.Collections.Generic;
using System.Collections;
using System.Diagnostics;

namespace YieldDemo
{
    public class States1
    {
          public static IEnumerable<string> GetNames()
        {
            yield return "Alabama";
            yield return "Alaska";
            yield return "Arizona";
            yield return "Arkansas";
            yield return "California";
            yield return "Others ...";
        }
    }

    public class States2
    {
        private static readonly IList<string> _names;

        static States2()
        {
            _names = new List<string>() {"Alabama", 
                                     "Alaska",
                                     "Arizona",
                                     "Arkansas",
                                     "California",
                                     "Others ..." };

        }

        public static IList<string> GetNames()
        {
            return _names;
        }
    }

    public class Program
    {

        static void Main()
        {    
            Test(States2.GetNames());
            Test(States1.GetNames());

            Console.ReadLine();
        }

        public static void Test(dynamic state)
        {
            Stopwatch stopwatch = new Stopwatch();

            stopwatch.Start();
            Iterate(state);            
            stopwatch.Stop();

            Console.WriteLine("Time elapsed: {0}", stopwatch.Elapsed);
        }

        public static void Iterate(dynamic itemList)
        {
            var enumerator = itemList.GetEnumerator();

            while (enumerator.MoveNext())
            {
                Console.WriteLine(enumerator.Current);
            }
        }
    }
}

谢谢

【问题讨论】:

  • @SLaks:不,我相信它在运行时会因为显式接口实现而失败。 (它在同一个组件中,所以内部很好。)

标签: c# .net


【解决方案1】:

问题在于迭代器块实现使用显式接口实现来实现IEnumerable&lt;T&gt;...,而显式接口实现通常不能很好地与动态类型配合使用。 (您不需要使用迭代器块来查看。请参阅my article on Gotchas in Dynamic Typing 了解更多详细信息。)

您可以使用 foreach 进行迭代:

public static void Iterate(dynamic itemList)
{
    foreach (dynamic item in itemList)
    {
        Console.WriteLine(item);
    }
}

这有一个额外的好处,它会为您处理迭代器,而您之前的代码没有这样做:)

或者,您可以为Iterate 添加重载以采用IEnumerableIEnumerable&lt;T&gt;,并让Test 内的执行时重载解析做正确的事情(因为state 也是dynamic)。

【讨论】:

  • 感谢@Jon Skeet 的回答
【解决方案2】:

它失败是因为yield 代码explicitly implements 其接口(包括您尝试使用的GetEnumerator)生成的IEnumerable&lt;string&gt; 类。你可以这样调用方法:

public static void Iterate(dynamic itemList)
{
    var enumerator = ((IEnumerable)itemList).GetEnumerator();

    while (enumerator.MoveNext())
    {
        Console.WriteLine(enumerator.Current);
    }
}

或者,由于我可以在这里看到的任何原因,您不需要 dynamic,也许只是:

public static void Iterate(IEnumerable itemList)
{
    var enumerator = itemList.GetEnumerator();

    while (enumerator.MoveNext())
    {
        Console.WriteLine(enumerator.Current);
    }
}

或者

public static void Iterate<T>(IEnumerable<T> itemList)

【讨论】:

  • 感谢@Tim S. 的回答
猜你喜欢
  • 1970-01-01
  • 2010-12-21
  • 2011-05-14
  • 2013-09-28
  • 1970-01-01
  • 2020-02-18
  • 2012-11-26
  • 2020-08-04
  • 1970-01-01
相关资源
最近更新 更多