[英]Can I bypass Console.ReadKey() issue when input is redirected?
I am a C# teacher and I wrote some automated HW checker for my students. 我是C#老师,并且为我的学生编写了一些自动化的硬件检查器。 The students write C# Console Applications.
学生编写C#控制台应用程序。 My HW checker is based on input redirection so I can test their code on my own generated input.
我的硬件检查器基于输入重定向,因此我可以在自己生成的输入上测试其代码。
The problem is that students sometimes end their program with a Console.ReadKey()
instruction (They do so just to make the execution window not close when they ran the program under F5 - Debug). 问题在于,学生有时会以
Console.ReadKey()
指令结束程序(这样做是为了使他们在F5-调试下运行程序时不会关闭执行窗口)。 The Console.ReadKey()
crashes when ran under input redirection with the following exception: 在输入重定向下运行时,
Console.ReadKey()
崩溃,但以下情况除外:
System.InvalidOperationException: Cannot read keys when either application does not have a console or when console input has been redirected from a file.
System.InvalidOperationException:当任一应用程序没有控制台或控制台输入已从文件重定向时,无法读取键。
Do I have any way to "bypass" this problem (without altering the students code)? 我有什么办法“绕过”这个问题(无需更改学生代码)? Maybe tell
Console
to ignore ReadKey
instructions? 也许告诉
Console
忽略ReadKey
指令?
I see a clear case for a Dependency Injection pattern. 我看到了依赖注入模式的明确案例。
Let's build a simple example, with Read
, ReadLine
and WriteLine
functionalities polymorphically: your students must write a homework in which a number given in the Console.ReadLine()
must be parsed as int
and returned to the Console
Window. 让我们以一个具有多态的
Read
, ReadLine
和WriteLine
功能的简单示例为例:您的学生必须编写家庭作业,其中Console.ReadLine()
给出的数字必须解析为int
并返回到Console
窗口。
Usually a student writes something like: 通常,一个学生写这样的东西:
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();
}
}
Now, instead, create an interface
for the Console
functionalities: 现在,改为为
Console
功能创建一个interface
:
public interface IOutput
{
void Read();
string ReadLine();
void WriteLine(string text);
}
A student must create a Homework
class
that wraps all the required homework code, using an IOutput
instance in this way: 学生必须使用
IOutput
实例通过以下方式创建包装所有必需的作业代码的Homework
class
:
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();
}
}
The Main
becomes: Main
变成:
static void Main(string[] args)
{
var h = new HomeWork(new ConsoleOutput());
h.Run();
}
You give them also the ConsoleOutput
class
: 您还给他们提供了
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);
}
}
So the use it instead of call directly Console.Read()
etc. 因此,使用它代替直接调用
Console.Read()
等。
The student must pass to you not the entire Application
, but only the Homework
class
. 学生不必将整个
Application
传递给您,而是仅将Homework
class
传递给您。
You can create a test class that use the Homework
class
with some test implementations of IOutput
like the followings: 您可以创建将
Homework
class
与IOutput
一些测试实现结合使用的测试类,如下所示:
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; }
}
The test class can be something like this: 测试类可以是这样的:
[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]);
}
}
If you need only to wrap the Console.Read()
method, feel free to simplify all this code, but IMHO I thought that a wider view on this possible solution would have been useful anyway. 如果只需要包装
Console.Read()
方法,请随意简化所有这些代码,但是恕我直言,我认为,对这种可能的解决方案进行更广泛的了解还是很有用的。
If the executables are in IL, you can create an easy application that uses ILDASM . 如果可执行文件在IL中,则可以创建一个使用ILDASM的简单应用程序。
The key point is: disassemble the executable with ILDASM into a text file/stream, look for any call to Console.Read
and remove it, than recompile it and run. 关键点是:使用ILDASM将可执行文件反汇编为文本文件/流,查找对
Console.Read
任何调用。 Console.Read
并删除它,然后重新编译并运行。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.