【问题标题】:Console.WriteLine and generic ListConsole.WriteLine 和通用列表
【发布时间】:2010-09-08 08:25:36
【问题描述】:

我经常发现自己在编写这样的代码:

List<int> list = new List<int> { 1, 3, 5 };
foreach (int i in list) {
    Console.Write("{0}\t", i.ToString()); }
Console.WriteLine();

最好是这样的:

List<int> list = new List<int> { 1, 3, 5 };
Console.WriteLine("{0}\t", list);

我怀疑有一些聪明的方法可以做到这一点,但我没有看到。有没有人有比第一个块更好的解决方案?

【问题讨论】:

    标签: c# generics console list


    【解决方案1】:

    这样做:

    list.ForEach(i => Console.Write("{0}\t", i));
    

    编辑:对于其他已回复的人 - 他希望他们都在同一行,他们之间有制表符。 :)

    【讨论】:

    • 如果您的环境中没有可用的ForEach(如我),您可以使用implement your own
    【解决方案2】:

    另一种方法,只是为了好玩:

    Console.WriteLine(string.Join("\t", list));
    

    【讨论】:

    • List 对我不起作用。我得到了 InvalidCastException。
    • 我也得到了InvalidCastException - 答案不正确。此外,当我尝试使用 List&lt;CustomType&gt; 并为 CustomType 实现隐式和显式转换时,结果相同
    • 您不需要将列表转换为字符串并转换为数组。 string.Join 将接受一个列表,因为有一个重载需要一个 IEnumerable.parameter,如 的 IEnumerable (List) (在本例中为 T = int),因此 List 将被迭代并 int.ToString( ) 将在 Join() 方法中调用。 Console.WriteLine(string.Join("\t", list)); docs.microsoft.com/en-us/dotnet/api/…
    【解决方案3】:

    如果有一段代码根据 Don't Repeat Yourself 一直重复,你应该把它放在你自己的库中并调用它。考虑到这一点,在这里获得正确答案有两个方面。首先是调用库函数的代码简洁明了。第二个是 foreach 的性能影响。

    首先让我们考虑一下调用代码的清晰性和简洁性。

    您可以通过多种方式执行 foreach:

    1. for 循环
    2. foreach 循环
    3. Collection.ForEach

    在所有的 foreach List.ForEach 方法中,使用lamba 是最清晰和最简洁的。

    list.ForEach(i => Console.Write("{0}\t", i));
    

    所以在这个阶段,List.ForEach 可能是要走的路。然而这有什么表现呢?确实,在这种情况下,写入控制台的时间将决定代码的性能。当我们了解特定语言功能的性能时,我们当然至少应该考虑一下。

    根据Duston Campbell's performance measurements of foreach,在优化代码下迭代列表的最快方法是使用 for 循环而不调用 List.Count。

    然而,for 循环是一个冗长的结构。它也被视为一种非常迭代的做事方式,与当前的功能习语趋势不符。

    那么我们能否获得简洁、清晰和性能?我们可以通过使用扩展方法。在理想情况下,我们会在 Console 上创建一个扩展方法,它接受一个列表并用分隔符写入它。我们不能这样做,因为 Console 是一个静态类,而扩展方法仅适用于类的实例。相反,我们需要将扩展​​方法放在列表本身(根据 David B 的建议):

    public static void WriteLine(this List<int> theList)
    {
      foreach (int i in list)
      {
        Console.Write("{0}\t", t.ToString());
      }
      Console.WriteLine();
    }
    

    这段代码将在很多地方使用,所以我们应该进行以下改进:

    • 我们应该使用最快的方法来迭代集合,而不是使用 foreach,这是一个带有缓存计数的 for 循环。
    • 目前只有 List 可以作为参数传递。作为一个库函数,我们可以通过少量的努力来概括它。
    • 使用 List 将我们限制为仅使用列表,使用 IList 允许此代码也可以使用数组。
    • 由于扩展方法将在 IList 上,我们需要更改名称以更清楚地显示我们要写入的内容:

    函数代码如下所示:

    public static void WriteToConsole<T>(this IList<T> collection)
    {
        int count = collection.Count();
        for(int i = 0;  i < count; ++i)
        {
            Console.Write("{0}\t", collection[i].ToString(), delimiter);
        }
        Console.WriteLine();
    }
    

    我们可以通过允许客户端传入分隔符来进一步改进这一点。然后我们可以提供第二个函数,使用标准分隔符写入控制台,如下所示:

    public static void WriteToConsole<T>(this IList<T> collection)
    {
        WriteToConsole<T>(collection, "\t");
    }
    
    public static void WriteToConsole<T>(this IList<T> collection, string delimiter)
    {
        int count = collection.Count();
        for(int i = 0;  i < count; ++i)
        {
             Console.Write("{0}{1}", collection[i].ToString(), delimiter);
        }
        Console.WriteLine();
    }
    

    现在,鉴于我们想要一种将列表写入控制台的简短、清晰的高性能方式,我们有一个。这是完整的源代码,包括使用库函数的演示:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    
    namespace ConsoleWritelineTest
    {
        public static class Extensions
        {
            public static void WriteToConsole<T>(this IList<T> collection)
            {
                WriteToConsole<T>(collection, "\t");
            }
    
            public static void WriteToConsole<T>(this IList<T> collection, string delimiter)
            {
                int count = collection.Count();
                for(int i = 0;  i < count; ++i)
                {
                    Console.Write("{0}{1}", collection[i].ToString(), delimiter);
                }
                Console.WriteLine();
            }
        }
    
        internal class Foo
        {
            override public string ToString()
            {
                return "FooClass";
            }
        }
    
        internal class Program
        {
    
            static void Main(string[] args)
            {
                var myIntList = new List<int> {1, 2, 3, 4, 5};
                var myDoubleList = new List<double> {1.1, 2.2, 3.3, 4.4};
                var myDoubleArray = new Double[] {12.3, 12.4, 12.5, 12.6};
                var myFooList = new List<Foo> {new Foo(), new Foo(), new Foo()};
                // Using the standard delimiter /t
                myIntList.WriteToConsole();
                myDoubleList.WriteToConsole();
                myDoubleArray.WriteToConsole();
                myFooList.WriteToConsole();
                // Using our own delimiter ~
                myIntList.WriteToConsole("~");
                Console.Read();
            }
        }
    }
    

    ================================================ ========

    您可能认为这应该是答案的结尾。但是,可以进行进一步的概括。从 fatcat 的问题中不清楚他是否总是在向控制台写信。也许在 foreach 中还有其他事情要做。在那种情况下,Jason Bunting 的回答将给出一般性。这是他的回答:

    list.ForEach(i => Console.Write("{0}\t", i));
    

    除非我们对扩展方法进行进一步改进并添加 FastForEach,如下所示:

    public static void FastForEach<T>(this IList<T> collection, Action<T> actionToPerform)
        {
            int count = collection.Count();
            for (int i = 0; i < count; ++i)
            {
                actionToPerform(collection[i]);    
            }
            Console.WriteLine();
        }
    

    这允许我们使用尽可能快的迭代方法对集合中的每个元素执行任意代码

    我们甚至可以将 WriteToConsole 函数更改为使用 FastForEach

    public static void WriteToConsole<T>(this IList<T> collection, string delimiter)
    {
         collection.FastForEach(item => Console.Write("{0}{1}", item.ToString(), delimiter));
    }
    

    所以现在整个源代码,包括 FastForEach 的示例用法是:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    
    namespace ConsoleWritelineTest
    {
        public static class Extensions
        {
            public static void WriteToConsole<T>(this IList<T> collection)
            {
                WriteToConsole<T>(collection, "\t");
            }
    
            public static void WriteToConsole<T>(this IList<T> collection, string delimiter)
            {
                 collection.FastForEach(item => Console.Write("{0}{1}", item.ToString(), delimiter));
            }
    
            public static void FastForEach<T>(this IList<T> collection, Action<T> actionToPerform)
            {
                int count = collection.Count();
                for (int i = 0; i < count; ++i)
                {
                    actionToPerform(collection[i]);    
                }
                Console.WriteLine();
            }
        }
    
        internal class Foo
        {
            override public string ToString()
            {
                return "FooClass";
            }
        }
    
        internal class Program
        {
    
            static void Main(string[] args)
            {
                var myIntList = new List<int> {1, 2, 3, 4, 5};
                var myDoubleList = new List<double> {1.1, 2.2, 3.3, 4.4};
                var myDoubleArray = new Double[] {12.3, 12.4, 12.5, 12.6};
                var myFooList = new List<Foo> {new Foo(), new Foo(), new Foo()};
    
                // Using the standard delimiter /t
                myIntList.WriteToConsole();
                myDoubleList.WriteToConsole();
                myDoubleArray.WriteToConsole();
                myFooList.WriteToConsole();
    
                // Using our own delimiter ~
                myIntList.WriteToConsole("~");
    
                // What if we want to write them to separate lines?
                myIntList.FastForEach(item => Console.WriteLine(item.ToString()));
                Console.Read();
            }
        }
    }
    

    【讨论】:

    • 这是一个非常好的答案!虽然我不喜欢在通用列表中使用像 WriteToConsole 这样的扩展方法的想法。这显然违反了单一职责模式。我不希望一个列表对控制台有任何了解,无论是在其实现中还是在扩展方法中。
    • 是的,我想你的选择取决于你喜欢什么,哪个更关心......
    【解决方案4】:
    List<int> list = new List<int> { 1, 3, 5 };
    list.ForEach(x => Console.WriteLine(x));
    

    编辑:该死!花了太长时间打开 Visual Studio 来测试它。

    【讨论】:

    • 你一定比较初级——谁需要Visual Studio?我有 CLR 在我的脑海中运行。 J/K
    【解决方案5】:
    new List<int> { 1, 3, 5 }.ForEach(Console.WriteLine);
    

    【讨论】:

      【解决方案6】:
              List<int> a = new List<int>() { 1, 2, 3, 4, 5 };
              a.ForEach(p => Console.WriteLine(p));
      

      编辑:啊,他打败了我。

      【讨论】:

        【解决方案7】:
        list.ForEach(x=>Console.WriteLine(x));
        

        【讨论】:

          【解决方案8】:

          你也可以加入:

          var qwe = new List<int> {5, 2, 3, 8};
          Console.WriteLine(string.Join("\t", qwe));
          

          【讨论】:

            【解决方案9】:
            public static void WriteLine(this List<int> theList)
            {
              foreach (int i in list)
              {
                Console.Write("{0}\t", t.ToString());
              }
              Console.WriteLine();
            }
            

            那么,稍后……

            list.WriteLine();
            

            【讨论】:

              猜你喜欢
              • 2011-04-29
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2011-08-31
              • 1970-01-01
              • 2011-07-13
              相关资源
              最近更新 更多