2016-11-12 65 views
1

我是C#老师,我为我的学生写了一些自动化的HW检查器。 学生编写C#控制台应用程序。我的硬件检查器基于输入重定向,所以我可以在我自己生成的输入上测试他们的代码。当输入被重定向时,我可以忽略Console.ReadKey()问题吗?

问题是学生有时会用Console.ReadKey()指令结束他们的程序(他们这样做只是为了使程序在F5下运行时不会关闭 - 调试)。该Console.ReadKey()崩溃时输入重定向下运行与以下异常:

System.InvalidOperationException:当任一应用程序没有控制台或在控制台输入已经从一个文件重定向无法读取键。

我有什么办法“绕过”这个问题(不改变学生代码)吗?也许告诉Console忽略ReadKey说明?

+3

你不能“绕过”它。代码必须写入,以便在输入重定向时不调用ReadKey()。使用[IsInputRedirected方法](http://stackoverflow.com/a/3453272/17034)。或者指导学生不要使用ReadKey()。或者ReadLine()。教他们如何在Main()的最后一个大括号处设置断点,以便他们不需要这样做会很有用。 –

+0

使用Teensy(或其他任何东西)来模拟键入您的内容的键盘。那么你将不需要重定向输入,所以ReadKey将起作用! – wablab

回答

1

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

关键问题是:用ILDASM将可执行文件反汇编到文本文件/流中,寻找任何对Console.Read的调用并将其删除,然后重新编译并运行。

2

我看到了一个明确的情况依赖注入模式。

让我们建立一个简单的例子,用ReadReadLineWriteLine功能多态:您的学生必须写功课,其中在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(); 
    } 
} 

现在,而是创建一个interfaceConsole功能:

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

学生必须创建一个Homeworkclass用于包装所有的必修功课代码,以这种方式使用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(); 
} 

你给他们也ConsoleOutputclass

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,但只有Homeworkclass

您可以创建与IOutput一些测试实现,如以下使用Homeworkclass一个测试类:

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()方法,可以简化所有这些代码,但恕我直言,我认为对这种可能的解决方案的更广泛的观点是有用的。

+0

非常感谢您的好意。虽然你的答案已经很好地解释了,并且是做到这一点的“正确”方式 - 由于解释学生在界面和依赖性方面的教学复杂性,我无法使用它 - 他们只是“Hello World”大一新生... – user2795947