这可以让您显示一些消息。它还允许传递您想要的任何对象,但是它将被转换为字符串。您还可以添加信息,错误和警告消息,每种消息,消息和消息的颜色都将匹配。
using System;
using System.Drawing;
using System.Windows.Forms;
namespace ConsoleWindow
{
public sealed partial class Console
{
private static volatile Console instance = new Console();
private static ConsoleForm form = new ConsoleForm();
public static Console Instance
{
get
{
return instance;
}
}
public static bool autoShow = true;
private static string newline = "\r\n";
private static string line = "================================================================================";
/// <summary>
/// Forces the prompt to go to the end of the text.
/// </summary>
private static void scrollToEnd()
{
form.consoleOutput.SelectionStart = form.consoleOutput.Text.Length;
form.consoleOutput.ScrollToCaret();
}
/// <summary>
/// Adds a message to the console.
/// </summary>
/// <param name="message">Message object to log.</param>
public static bool Log<T>(T message)
{
if (autoShow)
{
Show();
}
scrollToEnd();
form.consoleOutput.AppendText(message.ToString() + newline);
scrollToEnd();
return true;
}
/// <summary>
/// Adds an error message to the console.
/// </summary>
/// <param name="message">Message object to log.</param>
public static bool Error<T>(T message)
{
if (autoShow)
{
Show();
}
scrollToEnd();
form.consoleOutput.SelectionColor = Color.Red;
form.consoleOutput.SelectionLength = 0;
form.consoleOutput.AppendText("(!) " + message.ToString() + newline);
scrollToEnd();
form.consoleOutput.SelectionColor = form.consoleOutput.ForeColor;
return true;
}
/// <summary>
/// Adds a warning message to the console.
/// </summary>
/// <param name="message">Message object to log.</param>
public static bool Warning<T>(T message)
{
if (autoShow)
{
Show();
}
scrollToEnd();
form.consoleOutput.SelectionColor = Color.Yellow;
form.consoleOutput.SelectionLength = 0;
form.consoleOutput.AppendText(@"/!\ " + message.ToString() + newline);
scrollToEnd();
form.consoleOutput.SelectionColor = form.consoleOutput.ForeColor;
return true;
}
/// <summary>
/// Adds a warning error message to the console.
/// </summary>
/// <param name="message">Message object to log.</param>
public static bool Info<T>(T message)
{
if (autoShow)
{
Show();
}
scrollToEnd();
form.consoleOutput.SelectionColor = Color.LightBlue;
form.consoleOutput.SelectionLength = 0;
form.consoleOutput.AppendText("[!] " + message.ToString() + newline);
scrollToEnd();
form.consoleOutput.SelectionColor = form.consoleOutput.ForeColor;
return true;
}
/// <summary>
/// Clears the console text.
/// </summary>
public static void Clear()
{
form.consoleOutput.Clear();
bool autoShowOriginal = autoShow;
autoShow = false;
autoShow = autoShowOriginal;
}
/// <summary>
/// Clears the console text. Returns false on exception.
/// </summary>
/// <param name="filename">Filename path in a string</param>
/// <param name="log">Logs a message indicating the operation successfulness</param>
/// <param name="clear">Clears the console on success</param>
public static bool SaveToFile(string filename, bool log = true, bool clear = false)
{
try
{
System.IO.File.WriteAllLines(form.saveFile.FileName, form.consoleOutput.Lines);
if (clear)
{
Clear();
}
if (log == true)
{
Log(line);
Info("File saved: " + filename);
}
return true;
}
catch (System.IO.IOException e)
{
if (log == true)
{
Log(line);
Error("Failed to save: " + filename);
Error(e);
}
return false;
}
}
/// <summary>
/// Closes the console.
/// </summary>
public static void Hide()
{
form.Hide();
}
/// <summary>
/// Closes the console. Warning: output will be lost!
/// </summary>
public static void Close()
{
form.Hide();
Clear();
}
/// <summary>
/// Shows the console.
/// </summary>
public static void Show()
{
form.Show();
}
/// <summary>
/// Private form functions and elements.
/// </summary>
private class ConsoleForm : Form
{
private static System.ComponentModel.IContainer components = new System.ComponentModel.Container();
public RichTextBox consoleOutput = new RichTextBox();
public ContextMenuStrip consoleMenu = new ContextMenuStrip(components);
public ToolStripMenuItem consoleMenuSave = new ToolStripMenuItem();
public ToolStripMenuItem consoleMenuClose = new ToolStripMenuItem();
public SaveFileDialog saveFile = new SaveFileDialog();
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
this.Dispose(disposing);
}
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.consoleMenu.SuspendLayout();
this.SuspendLayout();
//
// consoleOutput
//
this.consoleOutput.BackColor = System.Drawing.Color.Black;
this.consoleOutput.BorderStyle = System.Windows.Forms.BorderStyle.None;
this.consoleOutput.ContextMenuStrip = this.consoleMenu;
this.consoleOutput.DetectUrls = false;
this.consoleOutput.Dock = System.Windows.Forms.DockStyle.Fill;
this.consoleOutput.Font = new System.Drawing.Font("Consolas", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.consoleOutput.ForeColor = System.Drawing.Color.Silver;
this.consoleOutput.Location = new System.Drawing.Point(0, 0);
this.consoleOutput.Name = "consoleOutput";
this.consoleOutput.ReadOnly = true;
this.consoleOutput.ScrollBars = System.Windows.Forms.RichTextBoxScrollBars.ForcedVertical;
this.consoleOutput.Size = new System.Drawing.Size(583, 261);
this.consoleOutput.TabIndex = 0;
this.consoleOutput.TabStop = false;
this.consoleOutput.Text = "";
//
// consoleMenu
//
this.consoleMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.consoleMenuSave,
this.consoleMenuClose
});
this.consoleMenu.Name = "consoleMenu";
this.consoleMenu.ShowImageMargin = false;
this.consoleMenu.Size = new System.Drawing.Size(107, 48);
//
// consoleMenuSave
//
this.consoleMenuSave.Name = "consoleMenuSave";
this.consoleMenuSave.Size = new System.Drawing.Size(106, 22);
this.consoleMenuSave.Text = "&Save to file";
this.consoleMenuSave.Click += new System.EventHandler(this.consoleMenuSave_Click);
//
// consoleMenuClose
//
this.consoleMenuClose.Name = "consoleMenuClose";
this.consoleMenuClose.Size = new System.Drawing.Size(106, 22);
this.consoleMenuClose.Text = "&Close";
this.consoleMenuClose.Click += new System.EventHandler(this.consoleMenuClose_Click);
//
// saveFile
//
this.saveFile.DefaultExt = "txt";
this.saveFile.Filter = "Text file (*.txt)|*.txt|All files|*.*";
this.saveFile.Title = "Save console output";
//
// consoleForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(583, 261);
this.Controls.Add(this.consoleOutput);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "consoleForm";
this.ShowIcon = false;
this.ShowInTaskbar = false;
this.Text = "Console";
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.consoleForm_FormClosing);
this.consoleMenu.ResumeLayout(false);
this.ResumeLayout(false);
}
public ConsoleForm()
{
InitializeComponent();
}
private void consoleMenuSave_Click(object sender, EventArgs e)
{
if (saveFile.ShowDialog() == DialogResult.OK)
{
Console.SaveToFile(saveFile.FileName);
}
}
private void consoleMenuClose_Click(object sender, EventArgs e)
{
Console.Close();
}
private void consoleForm_FormClosing(object sender, FormClosingEventArgs e)
{
if (e.CloseReason != CloseReason.ApplicationExitCall
|| e.CloseReason != CloseReason.TaskManagerClosing)
{
e.Cancel = true;
Console.Close();
}
}
}
}
}
我知道这是很长的代码。大部分只是设置元素的属性。大部分是从生成的代码中复制粘贴。我已尝试将其降至最低。
整个想法是将其放入文件中,即可使用。它应该显示在您的第一条消息上。可以很容易地禁用它。
我主要关心的是整个模式,这是...糟糕...真的很糟糕!我有一个带有部分类的名称空间,该部分类带有从
Form
类继承的私有类...但是,我找不到更好的方法来将表单保留在单独的类中并且仍然私有。就可读性而言,我还将犯下哪些其他罪行?
#1 楼
public sealed partial class Console
如果没有关联的设计师生成的代码,为什么为什么要使用
partial
类?提供partial
关键字是为了方便,它通过允许一个类的定义跨越多个文件来帮助组织代码。如果只有1个文件,则partial
关键字充其量是没有用的,而最糟糕的情况是令人困惑的。 .net控制台应用程序将具有。private static volatile Console instance = new Console();
为什么
Console
?为什么Console
?即使您要从多个线程访问该类,static
引用也会被静态初始化,因为volatile
只会增加无用的开销。查看该类的接口(例如,公共成员)可以给我一个有关为何字段为
instance
的答案-但是最佳实践告诉我们,如果班级的每个成员都将是volatile
,则班级本身也应该为static
。这是当前有效的代码:var console = new ConsoleWindow.Console();
然后,在没有实例成员可以调用的情况下,开发人员将全部使用WTF。通过使类
static
无效,就可以使构造函数的调用无效,并迫使用户调用静态成员-就像static
类一样。 。如果您的班级应为static
,则不需要它。而且,如果您真的想要一个Singleton,则应该有一个私有的默认构造函数,以防止其他代码创建您的类的实例...但是使类System.Console
是实现同一目标的更好方法。 /> private class ConsoleForm : Form
为什么嵌套?为什么
static
?为什么它不是static
类,而在专用的designer.cs文件中带有设计器代码?大部分只是设置元素的属性。大部分是从生成的代码中复制粘贴。
很抱歉,但没有。只是...不。
布尔逻辑在这里被破坏了:
if (e.CloseReason != CloseReason.ApplicationExitCall
|| e.CloseReason != CloseReason.TaskManagerClosing)
大声读出来,或者将逻辑求反。
这是错误的:
private void consoleMenuSave_Click(object sender, EventArgs e)
{
if (saveFile.ShowDialog() == DialogResult.OK)
{
Console.SaveToFile(saveFile.FileName);
}
}
您正在通过其静态成员访问父
private
类,但是您不需要嵌套类型就可以做到这一点。不论是否嵌套,该窗口都与该父级partial
类紧密耦合,并且您在这里拥有的是视图级别的演示者逻辑。使表格独立存在。
我找不到更好的方法将表单保留在单独的类中并且仍然是私有的。
您不需要私有的表单。您只需要知道更新表单将无济于事,因为表单中没有逻辑...正确完成后。
将您的
Console
类重命名为Console
,删除所有Console
-ness(是,请抓取我在该答案的第一部分中上面提到的所有内容!),并使ConsolePresenter
在其构造函数中采用一个static
实例。然后从那里获取该嵌套类型,使其与设计器代码所属的设计器代码(在.designer.cs文件中),使其实现
ConsolePresenter
接口,而不是在表单代码中实现逻辑,并且不直接调用presenter(/ IConsoleView
)方法,而引发一个事件,指出“嘿,我是表单-用户刚刚单击了“保存”按钮,您要执行任何操作吗?” 您将需要
IConsoleView
,因此请创建一个Console
类,其中包括它们:public class ConsoleLinesEventArgs : EventArgs
{
public ConsoleLinesEventArgs(string[] lines)
{
Lines = lines;
}
public string[] Lines { get; private set; }
}
现在使用它:
private void consoleMenuSave_Click(object sender, EventArgs e)
{
OnPromptToSave();
}
public event EventHandler<ConsoleLinesEventArgs> PromptToSave;
protected void OnPromptToSave()
{
var handler = PromptToSave;
if (handler != null)
{
var args = new ConsoleLinesEventArgs(consoleOutput.Lines);
handler(this, args);
}
}
Lines
事件是EventArgs
接口的一部分ace,演示者可以注册:public Console(IConsoleView view)
{
view.PromptToSave += view_PromptToSave;
}
private void view_PromptToSave(object sender, ConsoleLinesEventArgs e)
{
using (var dialog = new SaveFileDialog())
{
if (dialog.ShowDialog() == DialogResult.OK)
{
SaveToFile(dialog.FileName, e.Lines);
}
}
}
请注意
PromptToSave
实例的生命周期非常短:因为IConsoleView
实现了dialog
接口,所以最好使任何实例都尽可能短命,并将该实例包装在SaveFileDialog
块中,以确保正确处置。 br />看看IDisposable
的实现方式... System.IO.File.WriteAllLines(form.saveFile.FileName, form.consoleOutput.Lines);
在文件顶部添加
using
,并摆脱这些冗长的命名空间限定符:是SaveToFile
想打电话。现在,如果该方法正在从视图上的using System.IO;
实例读取文件名,为什么还要传递File.WriteAllLines
参数?此方法甚至不需要了解视图,更不用说其fileName
成员了,该成员应该是私有的。通过传递
SaveFileDialog
的文件名和consoleOutput
的SaveFileDialog
,您将拥有所需的一切将行写入文件中-您不负责获取有问题的行。一旦视图仅通过事件与演示者对话,并且演示者仅通过其公共接口访问视图,那么您就可以删除该不稳定的Singleton,并使成员成为非静态成员,并让该类实现一些
Lines
接口,客户端代码可以将其用作可模拟依赖项,而不必与某些静态辅助方法紧密耦合。代码的最大问题是,您拥有A类(取决于类B)和B类(取决于类A)。重构为Model-View-Presenter模式将使该意大利面条解开。
MVP 101
让我们简化一下(这篇文章已经很长了嗯)-假设只有一个“导出”按钮和一个文本框,并且与该按钮关联的命令需要文本框的内容-文本框是一个实现细节,就像按钮一样。演示者只需知道按钮被单击即可:
public interface IFooView
{
event EventHandler<ExportEventArgs> ExportContent;
DialogResult ShowDialog();
}
当用户单击按钮时,视图将引发
ConsoleLinesEventArgs
事件,以向演示者表示用户要导出文本框的内容。 .NET框架提供了一种携带事件数据的机制-IConsolePresenter
类的作用是:public class ExportEventArgs : EventArgs
{
public ExportEventArgs(string content)
{
Content = content;
}
public string Content { get; private set; }
}
然后,您将拥有自己的表格,实现该
ExportContent
接口: />设计人员必须具有默认构造函数才能实例化表单;通过运行ExportEventArgs
方法,它知道如何实例化和初始化表单上的所有控件-该代码是由设计人员生成的,不应被篡改。您甚至不需要查看IFooView
文件,如果那里的代码需要更改,最好使用设计器,让设计器重新生成文件。接下来,事件声明:
public partial class FooView : Form, IFooView
{
public FooView()
{
InitializeComponents();
}
public event EventHandler<ExportEventArgs> ExportContent;
private void OnExportContent()
{
var handler = ExportContent;
if (handler != null)
{
var args = new ExportEventArgs(TextBox1.Text);
handler(this, args);
}
}
private void ExportButton_Click(object sender, EventArgs e)
{
OnExportContent();
}
}
事件是多播委托-它们可以有多个订阅者。该框架为无参数事件提供
InitializeComponents
,为参数化事件提供通用FooView.designer.cs
:遵循这些委托类型是遵循“最少惊喜原则”的最佳方法,因为.NET开发人员希望事件处理程序具有EventHandler
签名-但从理论上讲没有什么可以阻止您使用不同的委托人类型声明事件,除非... 。代表类型明确定义了什么参数,将在需要修改事件以添加,删除或修改参数的那一刻立即中断所有客户端代码:使用
EventHandler<T>
派生的参数解决了此问题,因为坚持模式您的客户端代码将始终有效,因为只要方法具有void:(object, EventArgs)
签名,它就可以处理任何事件,因为在C#中,委托签名中的void
可以完美地由采用EventArgs
的处理程序处理。 br />因此,事件可以有订阅者-如果您尝试引发没有订阅者的事件,则会引发EventArgs
。这就是为什么您看到以下内容的原因:public event EventDelegateType EventName;
(object,EventArgs)
是事件的线程本地副本;提高该副本而不是直接引发事件,使事件引发线程变得安全:另一个线程可以去取消注册FooEventArgs
分配与EventArgs
检查之间的最后一个处理程序,并且不会发生异常,因为您正在引发事件的线程本地副本。您不必这样做,但是这样做是最佳实践,并且不这样做肯定会在将来咬住您。注意
NullReferenceException
作为handler
参数被传递:这也是惯例和最佳做法-实践。如果发生无参数事件,您将传递handler =
而不是handler != null
-这也是一个约定。与执行应完成的任务有关。演示者是该逻辑所属的地方:
var handler = ExportContent;
if (handler != null)
{
var args = new ExportEventArgs(TextBox1.Text);
handler(this, args);
}
演示者负责实现逻辑。它也可以依赖于其他服务-例如写入数据库所需的
this
逻辑;您可以在那里实现sender
逻辑,但是如果您有几个需要实现的命令,它将很快变得多余:您可以将其抽象到另一个接口之后,然后将该对象注入到您的构造函数中:public class FooPresenter
{
private readonly IFooView _view;
public FooPresenter(IFooView view)
{
_view = view;
_view.ExportContent += View_ExportContent;
}
public void Show()
{
_view.ShowDialog();
}
private void View_ExportContent(object sender, ExportEventArgs e)
{
var data = e.Content;
// do something with data
}
}
Voilà!
您会得到什么?
一个不依赖任何内容且不实现任何逻辑的视图-基本上,一个视图就是这样:一个演示文稿-专注于类的对象,它严格负责表示逻辑。
依赖于抽象的表示者,因此您可以模拟
EventArgs.Empty
依赖性并编写实际上不需要提出表单的自动化测试。模型可以在视图和演示者之间传递数据。
#2 楼
private static string newline = "\r\n";
这是非常错误的。特别是由于.NET的开源,导致在非Windows操作系统上使用C#的可能性增加,我们不应该依赖于特定于平台的换行符。
正确的方法看起来像这样:
private static string newline = Environment.NewLine;
至此,我们只是提供了一个可疑实用程序的别名。
看看如何我们在日志,错误,警告和信息之间有很多重复。这是不必要的。
我们需要一个私有的内部函数来处理我们正在复制的所有内容,然后
Log
,Error
,Warn
和Info
方法只是公开地公开了调用此方法的各种方法。private static bool ConsolePrint(String message, Color color)
{
if (autoShow)
{
Show();
}
scrollToEnd();
form.consoleOutput.SelectionColor = color;
form.consoleOutput.SelectionLength = 0;
form.consoleOutput.AppendText(message + Environment.NewLine);
scrollToEnd();
form.consoleOutput.SelectionColor = form.consoleOutput.ForeColor;
return true;
}
现在我们将其包装为其他方法。
public static bool Log<T>(T message)
{
return ConsolePrint(message.ToString, form.consoleOutput.ForeColor);
}
public static bool Error<T>(T message)
{
return ConsolePrint("(!) " + message.ToString, Color.Red);
}
// etc...
评论
\ $ \ begingroup \ $
这实际上是一个不错的选择。我没有意识到!实际上,直到几天前,我对.net的开源还是未知的。这确实是一个不错的提示。谢谢!
\ $ \ endgroup \ $
–伊斯梅尔·米格尔(Ismael Miguel)
15年8月16日在21:49
\ $ \ begingroup \ $
您忘记了ConsolePrint上的问题。
\ $ \ endgroup \ $
–伊斯梅尔·米格尔(Ismael Miguel)
15年8月16日在22:14
\ $ \ begingroup \ $
与.NET可能有所不同,但是\ n通常在编程语言中被定义为-the-换行符。例如,在C语言中,\ r \ n会产生与普通编译器上纯\ n相同的结果-单独的\ r仍会按预期工作(将光标移至行的开头)。
\ $ \ endgroup \ $
–更清晰
15年8月16日在23:19
\ $ \ begingroup \ $
我们不应该猜测。我们应该使用语言来提供给我们的属性,这些语言可以检查我们所运行的环境并使用正确的字符。
\ $ \ endgroup \ $
– nhgrif
15年8月16日在23:25
#3 楼
我对WinForms或这种应用程序的设计方式不是很熟悉,因此本文将做一个简短的回顾。而不是像在这里那样在字符串中键入80个重复的字符:
private static string line = "================================================================================";
如果您拥有.NET 4.0,则可以执行以下操作:
private static string line = String.Concat(Enumerable.Repeat("=", 80));
您也可以执行此操作(感谢@ Mat'sMug):
private static string line = new string('=', 80);
此行:
if (log == true)
可以简单地缩写为:
if (log)
另外,由于您已经是
using
命名空间System
,此行:catch (System.IO.IOException e)
可以缩写为:
catch (IO.Exception e)
还有其他一些地方,我注意到您使用了前缀
System
。这些可以删除。评论
\ $ \ begingroup \ $
String.Concat(Enumerable.Repeat(“ =”,80));是否会降低性能?相对于文字字符串?我的直觉说可能有。
\ $ \ endgroup \ $
– nhgrif
15年8月16日在21:39
\ $ \ begingroup \ $
问题是我不确定我将始终拥有.NET 4.0。实际上,我已经使其与.NET 2.0及更高版本一起运行。是的,它可以毫无问题地在所有这些版本中编译和运行。我一直在迅速寻找解决方法,但他们却忽略了它。
\ $ \ endgroup \ $
–伊斯梅尔·米格尔(Ismael Miguel)
15年8月16日在21:40
\ $ \ begingroup \ $
@nhgrif可能确实如此,因为调用了两种方法,第一种方法只是在内存中存储一些字符。但是,它看起来确实更干净,并且允许使用常量代替80。
\ $ \ endgroup \ $
– SirPython
15年8月16日在21:41
\ $ \ begingroup \ $
@nhgrif我敢肯定它可以用于较大的尺寸,但是对于80的尺寸,我怀疑它是否会起到很大的作用。
\ $ \ endgroup \ $
– Ethan Bierlein
15年8月16日在21:49
\ $ \ begingroup \ $
字符串类具有用于重复字符的(char,int)构造函数。
\ $ \ endgroup \ $
–马修·金登(Mathieu Guindon)♦
15年8月16日在22:00
#4 楼
/// <summary>
/// Closes the console. Warning: output will be lost!
/// </summary>
public static void Close()
{
form.Hide();
Clear();
}
您说要关闭表格,但实际上只是将其隐藏并清除数据。实现
Form
的类型具有Close()
方法。在每个文件中放置单个类/枚举/接口。这将使查找各种类变得容易,因为每个文件与其包含的类型具有相同的名称,并且每个文件都有一个职责。 br />
这看起来很混乱,随着项目的扩大,将很难控制。现在该利用MVP模式了。
首先,创建您的视图必须实现的接口。其中可能包括
void Close()
和DialogResult ShowDialog()
,还可能包括void Hide()
和其他直接控制表单的自定义方法。接下来,创建您的表单。用于初始化表单的所有代码都在设计器文件中(但您无需手动将其放置在此处,请使用设计器窗口创建输出)。
现在您创建演示者并DI表单使用您的自定义接口类型,例如
public MyPresenter(IView view)
。从那里调用ShowDialog()
并使用结果来决定要做什么。如果有多个可以单击的按钮,则可能需要使用Show()
和触发事件。演示者将处理未直接绑定到视图的所有数据。如果要显示输出,则演示者应该有一个公共方法来获取输出,处理输出,并(通常是单个)调用视图来处理它。例如,这可以是演示者的基本轮廓:private IView _console; // assigned from the constructor argument
private static bool ConsolePrint(String message, Color color);
public static bool Log<T>(T message);
public static bool Error<T>(T message);
模型是您使用的任何支持方法和其他对象(例如枚举)。 >现在,您还可以编写单元测试以确保一切正常(您可能希望/需要与此同时使用Moq或其他单元测试框架)。
#5 楼
就可读性而言,我还将犯其他什么罪行?
您将要犯下一个罪行。这大约是一个文件中所需的最大内容量。如果您的命名空间增加,请确保每个大类都获取它自己的文件。它可以使事情井井有条,可维护,并为保持源代码管理日志的整洁(您正在使用源代码管理,对吗?)产生奇迹。
仔细看一下您的函数命名:
/// <summary>
/// Closes the console.
/// </summary>
public static void Hide()
{
form.Hide();
}
您的摘要指出即将结束。函数名称表示它正在隐藏。在我的英语词典中,这些不一样。除非这是我不熟悉的C#行话,否则这非常令人困惑。隐藏暗示它被推送到后台,而关闭暗示它被终止。
我也忍不住注意到您经常使用以下内容:
if (autoShow)
{
Show();
}
不要重复自己。您实际上是在整个项目中复制此构造。您可能希望将此类功能推入自己的include中,这些功能可能会也可能不属于您的命名空间。
评论
\ $ \ begingroup \ $
你是对的,我应该对所有输出都采用一种方法。关于关闭和隐藏,这是一个错误的措辞。我只是不知道该写些什么,因为该表格将被“关闭”。但是所有数据都将保留。但是,再次提示!
\ $ \ endgroup \ $
–伊斯梅尔·米格尔(Ismael Miguel)
15年8月16日在21:54
评论
\ $ \ begingroup \ $
哇!!!这是要吸收的大量信息!哇!你真让我震惊!今天我有很多阅读和执行的知识。十分感谢!这无疑对我有很大帮助!之所以说整个……是因为我在某个地方看到它。我想做一个单身人士和一个私人班级。这就是我这样做的原因。
\ $ \ endgroup \ $
–伊斯梅尔·米格尔(Ismael Miguel)
15年8月17日在8:21
\ $ \ begingroup \ $
@IsmaelMiguel添加了一些MVP-101教程,希望它可以使事情变得清晰。
\ $ \ endgroup \ $
–马修·金登(Mathieu Guindon)♦
15年8月18日在0:31
\ $ \ begingroup \ $
要阅读和实现的内容很多,但是今天我将使用这些新信息再次尝试。十分感谢!
\ $ \ endgroup \ $
–伊斯梅尔·米格尔(Ismael Miguel)
15年8月18日在8:44