【问题标题】:Reading text file into string array - why am I getting unexpected output?将文本文件读入字符串数组 - 为什么我会得到意外的输出?
【发布时间】:2019-02-14 15:07:56
【问题描述】:

尝试创建一个简单的 Hangman 游戏,其中读取外部文本(称为 words.txt)并将其中的字符串导入称为 WordsArray 的字符串数组。

程序编译得很好,但是,在显示填充数组的内容之前,它要求我输入文件名两次(参见下面的 foreach 循环)

有人可以确定为什么它在显示之前两次询问我的文件名吗?

(另外,更一般地说,我的重构是否适合这个简单的应用程序?)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;

namespace ConsoleApplication1
{
    class Program
    {
        static string [] LoadWords()
        { 
            bool repeat = true;
            while (repeat)
            {
                Console.WriteLine("Please enter the name of a file:");
                string filename = Console.ReadLine();

                try
                {
                    string[] WordsArray = File.ReadAllLines(filename);
                    if (WordsArray.Length == 0)
                        return null;
                    else
                        return WordsArray;
                }
                catch (FileNotFoundException msg)
                {
                    Console.WriteLine("\n Check the file exists!");
                }
            }
            return null;
        }

        static void DisplayWordsArray(string [] WordsArray)
        {
            foreach (string word in WordsArray)
                Console.WriteLine(word);
        }
        static void Main(string[] args)
        {
            string[] WordsArray= new string[10];
            if (LoadWords() != null)
            {
                Console.WriteLine("File Loaded...\n\n");
                WordsArray = LoadWords();
                DisplayWordsArray(WordsArray);
            }
            Console.ReadLine();
        }
    }
}

【问题讨论】:

  • 调用File.Exists( ... ) 来确定文件是否可行,而不是在不可行时捕获错误。
  • 它要求输入文件名两次,因为你调用了两次LoadWords()
  • 我知道对 LoadWords() 的调用出现在选择语句中,当其结果与 null 进行比较时。但是,在这种情况下,我认为返回的结果只会被调用......而不是其中的完整实现。
  • 每次调用方法时,都会执行方法代码。如果要多次使用返回值,请将其保存到变量中。
  • @ΩmegaMan 根据 Eric Lippert 的说法,OP 的设计是正确的 - 查看这篇博文的“外生异常”部分:blogs.msdn.microsoft.com/ericlippert/2008/09/10/…

标签: c# arrays text-files


【解决方案1】:

这是因为你调用了两次 LoadWords()。

你应该写:

string[] WordsArray= LoadWords();
if (WordsArray != null)
{
  Console.WriteLine("File Loaded...\n\n");
  DisplayWordsArray(WordsArray);
  ...

【讨论】:

  • 我可以再补充一个问题吗?我总是不得不使用“新”关键字来初始化一个数组。为什么在上面粘贴的解决方案中,没有使用“new”关键字,因为它正在“初始化”WordsArray? (除了使用方法的返回值这一显而易见的事实)
  • @Tiny - 当您调用File.ReadAllLines 时,文件被读入List<string>。然后在该列表上调用 ToArray 方法,该方法使用 new 关键字初始化数组,正如您所期望的那样。
【解决方案2】:

将逻辑更改为只回答一次问题,并处理已知的丢失文件可能性的失败。如果发生异常,请退出:

static string[] LoadWords()
{
    string[] WordsArray = null; 
    Console.WriteLine("Please enter the name of a file:");

    do
    {
        try
        {  
            string filename = Console.ReadLine();

            if (File.Exists(filename))
                WordsArray = File.ReadAllLines(filename);
            else
                Console.WriteLine($"{Environment.NewLine} File does not exist, try again: ");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"{Environment.NewLine} Unknown exception, exiting. {ex.Message}");
            return null;
        }
    }
     while (WordsArray == null)

    return WordsArray;
}

【讨论】:

    【解决方案3】:

    正如一些 cmets 和 Jesper 的回答中所提到的,重复是由于调用函数 LoadWords() 两次。这是错误的常见原因,并且往往是由于需要编写尽可能少的代码行(通过直接使用函数来消除变量声明和初始化)。

    除此之外,当错误可以通过其他方式处理时,故意触发异常是不明智的。从docs看下面的sn-p:

    对于可能发生但可能触发异常的情况,请考虑以能够避免异常的方式处理它们。

    由于存在方法File.Exists() 来检查文件是否存在,因此使用它而不是预期异常是正确的。

    START_EDIT: 因为文件可以被外部进程删除、锁定或以其他方式更改,所以使用 @RufusL 提到的 try...catch 块是谨慎的(另请参阅 Eric Lippert 的帖子 here)。过失! END_EDIT

    最后,你的重构很好:让一个方法处理一件事,并且处理好它几乎总是最好的。

    【讨论】:

    • 致命,白痴,烦人,外生……哈哈!这是一个有趣的阅读@RufusL。我将编辑我的答案,以免一些粗心的人落入陷阱。
    猜你喜欢
    • 2023-01-08
    • 1970-01-01
    • 2017-09-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-18
    • 2020-12-31
    相关资源
    最近更新 更多