当输入被重定向时,我可以绕过Console.ReadKey()问题吗?

本文关键字:ReadKey Console 问题 输入 重定向 我可以 | 更新日期: 2023-09-27 18:17:32

我是一名c#教师,我为我的学生写了一些自动的HW检查器。学生们编写c#控制台应用程序。我的HW检查器基于输入重定向,所以我可以在我自己生成的输入上测试他们的代码。

问题是学生有时用Console.ReadKey()指令结束他们的程序(他们这样做只是为了在F5 - Debug下运行程序时使执行窗口不关闭)。Console.ReadKey()在输入重定向下运行时崩溃,有以下例外:

系统。InvalidOperationException:当应用程序没有控制台或控制台输入已从文件重定向时,无法读取键。

我有任何方法来"绕过"这个问题(不改变学生的代码)?也许告诉Console忽略ReadKey的指令?

当输入被重定向时,我可以绕过Console.ReadKey()问题吗?

我清楚地看到了依赖注入模式。

让我们构建一个简单的例子,Read, ReadLineWriteLine功能的多态:你的学生必须写一个作业,其中Console.ReadLine()中给出的数字必须被解析为int并返回到Console窗口。

学生通常会这样写:

class Program
{
    static void Main(string[] args)
    {
        var stringValue = Console.ReadLine();
        int number;
        if (int.TryParse(stringValue, out number))
            Console.WriteLine($"The double of {number} is {number * 2}");
        else
            Console.WriteLine($"Wrong input! '{stringValue}' is not an integer!");
        Console.Read();
    }
}

现在,为Console功能创建一个interface:

public interface IOutput
{
    void Read();
    string ReadLine();
    void WriteLine(string text);
}

学生必须创建一个Homework class来封装所有必需的作业代码,使用IOutput实例,如下所示:

public class HomeWork
{
    private IOutput _output;
    public HomeWork(IOutput output)
    {
        _output = output;
    }
    public void Run()
    {
        _output.WriteLine("Give me an integer:");
        var stringValue = _output.ReadLine();
        int number;
        if (int.TryParse(stringValue, out number))
            _output.WriteLine($"The double of {number} is {number * 2}");
        else
            _output.WriteLine($"Wrong input! '{stringValue}' is not an integer!");
        _output.Read();
    }
}

Main变为:

static void Main(string[] args)
{
    var h = new HomeWork(new ConsoleOutput());
    h.Run();
}

你也给他们ConsoleOutput class:

public class ConsoleOutput : IOutput
{
    public void Read()
    {
        Console.Read();
    }
    public string ReadLine()
    {
        return Console.ReadLine();
    }
    public void WriteLine(string text)
    {
        Console.WriteLine(text);
    }
}

所以使用它而不是直接调用Console.Read()

学生必须传递给你的不是整个Application,而是Homework class

您可以创建一个使用Homework classIOutput的一些测试实现的测试类,如下所示:

public abstract class TestOutput : IOutput
{
    public TestOutput()
    {
        Outputs = new List<string>();
    }
    public void Read()
    {
        //do nothing?
    }
    public abstract string ReadLine();
    public void WriteLine(string text)
    {
        Outputs.Add(text);
    }
    public List<string> Outputs { get; set; }
}
public class TestOutputWithAValidNumber : TestOutput
{
    public TestOutputWithAValidNumber(int value)
    {
        Value = value;
    }
    public override string ReadLine()
    {
        return Value.ToString();
    }
    public int Value { get; }
}
public class TestOutputWithNotValidNumber : TestOutput
{
    public TestOutputWithNotValidNumber(string value)
    {
        Value = value;
    }
    public override string ReadLine()
    {
        return Value;
    }
    public string Value { get; }
}

测试类可以像这样:

[TestClass]
public class TestOutputClass
{
    [TestMethod]
    public void TestGoodNumber()
    {
        var testOutput = new TestOutputWithAValidNumber(1234);
        var h = new HomeWork(testOutput);
        h.Run();
        Assert.AreEqual(1234, testOutput.Value);
        Assert.AreEqual("Give me an integer:", testOutput.Outputs[0]);
        Assert.AreEqual("The double of 1234 is 2468", testOutput.Outputs[1]);
    }
    [TestMethod]
    public void TestWrongNumber()
    {
        var testOutput = new TestOutputWithNotValidNumber("foo");
        var h = new HomeWork(testOutput);
        h.Run();
        Assert.AreEqual("foo", testOutput.Value);
        Assert.AreEqual("Give me an integer:", testOutput.Outputs[0]);
        Assert.AreEqual("Wrong input! 'foo' is not an integer!", testOutput.Outputs[1]);
    }
}

如果您只需要包装Console.Read()方法,请随意简化所有这些代码,但恕我直言,我认为对这种可能的解决方案的更广泛的看法将是有用的。

如果可执行文件是IL格式,您可以创建一个使用ILDASM的简单应用程序。

关键是:用ILDASM将可执行文件反汇编成一个文本文件/流,查找对Console.Read的任何调用并删除它,然后重新编译并运行。