博格知识吸收者(译文)
By robot-v1.0
本文链接 https://www.kyfws.com/games/borg-knowledge-assimilator-zh/
版权声明 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
- 18 分钟阅读 - 8936 个词 阅读量 0博格知识吸收者(译文)
原文地址:https://www.codeproject.com/Articles/11092/Borg-Knowledge-Assimilator
原文作者:Sean Michael Murphy
译文由本站 robot-v1.0 翻译
前言
A simple game that accumulates facts and appears to learn by conversing with players asking yes and no questions.
一个简单的游戏,它积累了事实,并且看起来可以通过与玩家进行对话来学习,询问是与否.
背景(Background)
不久前,以星际大战为主题的Flash(A little while ago a Star Wars-themed Flash) 游戏(game) 进行了博客和电子邮件回合,让玩家尝试阻止Darth Vader.甚至讨论过(made the blog and email rounds, letting players try to stump Darth Vader. It was even discussed) 这里(here) 在CodeProject上.(on CodeProject.) 游戏的前提是达斯要求您思考一些事情,并通过询问您回答"是",“否”,“也许”,“有时"等问题来尝试猜测您的想法.游戏的乐趣是听到达斯(Darth)侮辱您,看到跳舞的突击队员(Storm Trooper)在结尾,以及其他UI异常,但有趣的是,还可以通过询问偶尔看起来像是真正有洞察力的问题来观察达斯(Darth)的话.(The premise of the game is that Darth asks you to think of something, and attempts to guess what you were thinking of by asking questions to which you answer “Yes”, “No”, “Maybe”, “Sometimes”, etc. Part of the fun of the game is hearing Darth insult you, seeing the dancing Storm Trooper at the end, and other UI fluff, but part of the fun is also watching Darth home in on your word by asking what occasionally seems like really insightful questions.) 玩了短时间的游戏后,我意识到它只是沿着一个问题和"事物"的树状结构行走.这款游戏与我在80年代早期使用TRS-80彩色计算机(显然没有Flash界面)时玩过的游戏的相似性令我震惊.那时,伪造AI程序的PC实现例如(After playing the game for a short time, I realized that it was just walking a tree structure of questions and “things”. I was struck by the similarity of the game to one I played back in the early 80’s on my TRS-80 Color Computer (obviously, without the Flash interface). Back then, PC implementations of fake AI programs like) 伊丽莎(Eliza) 当时风靡一时,决策树被视为实现有限AI的一种可能方法.该程序(不幸的是我不记得这个名字了)问你"是"和"不是"的问题,并且似乎是从经验中学到的.我们还很年轻,那时候很容易被打动.(were all the rage, and decision trees were seen as a possible way to implement limited AI. The program (unfortunately I can’t remember the name) asked you Yes and No questions, and seemed to learn from the experience. We were young and easily impressed back then.) 当然,这全都只是字符串操作,但这是"引人注目的"字符串操作.显然,它现在同样引人注目.看着办公室里的人们反复玩Sith游戏后,我开始对使用每个人的另一个最喜欢事实的反派Borg重新实现C#和XML的兴趣感兴趣.在本文中,我将向您展示如何编写模仿Sith游戏核心功能的游戏,并讨论控制台应用程序,XML序列化和过去的美好时光…(It was all just string manipulation, of course, but it was compelling string manipulation. Evidently it’s just as compelling now. After watching people in the office play the Sith game repeatedly, I became interested in re-implementing the original in C# and XML using everyone’s other favourite fact-hungry villain, the Borg. In this article, I’ll show you how to write a game that mimics the core functionality of the Sith game and talk about console applications, XML serialization and the good old days…)
算法(The Algorithm)
我认为在深入研究代码之前先进行示例运行是有益的.我将使用与图1所示相同的数据.由于用户输入始终为亮绿色,因此可以将用户输入与程序输出区分开.(I think it’s beneficial to talk through a sample run before we dive into the code. I’ll use the same data as is shown in Image 1. You can distinguish user input from program output because user input is always coloured bright green.)
当应用程序运行时,它会提示用户想到一个名词.在此示例中,用户将想到一只兔子.该应用程序询问其唯一的问题,并向用户征求是或否的答案.在我的资料中提供的数据库中,最初的问题是"它还活着(y/n)".这个问题(认为是兔子)的答案是"是”,因此用户输入" y".该应用程序在"是"侧遍历树,并在初始问题(乌龟)的"是"分支上读取名词.如果"是"节点是另一个(When the application runs, it prompts the user to think of a noun. In this example, the user will be thinking of a rabbit. The application asks its only question and solicits a yes or no answer from the user. In the database provided in my source, the initial question is “Is it alive (y/n)”. The answer to this question (thinking of a rabbit), is “Yes”, so the user enters “y”. The app traverses the tree on the “Yes” side and reads the noun on the Yes branch of the initial question (turtle). If the “Yes” node had been another) Question
对象,游戏将只询问该问题文本,然后继续遍历"(object, the game would have just asked that question text and continued to traverse the “) Yes
“和”(” and “) No
“问题的性质,直到(” properties of the questions until a) Noun
找到对象.但是,在此示例中,它已到达决策树此分支的末尾,并询问用户” turtle"是否是他们正在考虑的名词.(object was found. In this example, though, it has arrived at the end of this branch of the decision tree and asks the user if “turtle” was the noun which they were thinking.)
答案将是"否",因为我们正在考虑"兔子".现在,该应用程序切换到知识获取逻辑.该应用程序向用户询问他们在想的名词.用户键入"兔子".然后,应用程序会提出一个问题,以区分用户拥有的名词(兔子)和程序期望的名词(乌龟).用户可以输入诸如"是爬行动物"之类的问题.(The answer will be “no”, since we’re thinking “rabbit”. Now the app switches into knowledge acquisition logic. The application asks the user for the noun of which they were thinking. The user types “rabbit”. The app then solicits a question that distinguishes the noun the user had (rabbit) from the noun the program was expecting (turtle). The user can type some question like “Is it a reptile”.)
然后,该应用将新知识保存回原始数据文件,将其内部指针重置回根目录(The app then saves the new knowledge back to the original data file, resets its internal pointer back to the root) Question
对象,并询问用户是否要再次播放. XML数据文件是可移植的,可以通过电子邮件发送给人们玩.(object, and asks the user if they want to play again. The XML data file is portable, and can be emailed around to people to play.)
谈话很便宜,有时会造成混乱.您可以通过图像2中的这个简单示例来了解对象模型(以及描述对象模型的持久XML)如何演变.(Talk is cheap and occasionally confusing. You can see how the object model (and the persistent XML which describes the object model) evolves through this simple example in Image 2.)
代码(The Code)
对象模型中有两个基本构造:(There are two basic constructs in the object model,) Question
对象和(objects and) Noun
对象.(objects.) Noun
对象只有一个(objects just have a) Text
属性.(property.) Question
对象有一个(objects have a) Text
财产,以及(property, and) Yes
要么(or) No
根据用户给用户的响应所遵循的属性(properties that are followed based on the responses given by the user to the) Text
的属性(property of the) Question
.的(. The) Yes
要么(or) No
的属性(properties of the) Question
对象可以是其他(object can be other) Question
对象,或(objects, or) Noun
对象.由于节点可以是两种不同的类型之一,因此我创建了一个接口(objects. Since the nodes can be one of two different types, I created an interface both) Question
和(and) Noun
对象实现,称为(objects implement, called) IBorgElement
,并将其用作(, and use that as the type of the) Yes
和(and) No
Question
属性.我巩固了(properties. I consolidated the common elements of) Question
和(and) Noun
输入接口(字符串(types into the interface (a string) Text
财产和(property and a) Serialize
方法),但我不必这样做.(method) but I didn’t have to.)
using System;
using System.Xml;
namespace Borg {
public interface IBorgElement {
string Text {get;}
void Serialize(XmlDocument doc, XmlNode node);
}
}
名词对象(Noun Objects)
的(The) Noun
对象真的很简单.可以使用XML节点实例化它以帮助反序列化,也可以仅使用字符串来实例化它.(object is really straightforward. It can be instantiated with an XML node to aid in deserialization, and it can be instantiated with just the string for the) Text
属性:(property:)
public Noun(string text) {
_text = text;
}
public Noun(XmlNode node) {
XmlAttribute text = node.Attributes[Noun.TEXT_ATTRIBUTE_NAME];
if (text != null)
_text = text.InnerText;
}
Noun.TEXT_ATTRIBUTE_NAME
只是描述字符串名称的私有常量字符串(is just a private constant string describing the name of the) Text
中的属性(attribute in the) Noun
XML文档的节点.在这种情况下,它是"文本".我不喜欢让文字" Text"散布在类中以进行序列化和反序列化,因此我将其设为私有常量.您会在(node of the XML document. In this case, it’s “Text”. I didn’t like having the literal “Text” scattered around the class for serialization and deserialization, so I made it a private constant. You’ll see this in the) Question
上课了(class too.)
唯一有趣的方面(The only other interesting aspect of the) Noun
class是序列化代码.的(class is the serialization code. The) Noun
和(and) Question
将每个新事实添加到对象模型后,必须将对象序列化为XML文档.序列化(objects have to be serialized into an XML document after each new fact is added to the object model. Serialized) Noun
对象非常简单,在XML文件中看起来像这样:(objects are pretty trivial and look like this in the XML file:)
<Noun Text="turtle" />
它们在文档中的位置赋予了与其他名词的关系.序列化对象状态的代码如下所示:(It is their position in the document which confers the relationship to other nouns. The code to serialize the state of the object looks like this:)
void Borg.IBorgElement.Serialize(XmlDocument doc, XmlNode node) {
XmlNode noun = doc.CreateNode(XmlNodeType.Element,
Noun.NodeName, string.Empty);
XmlAttribute text = doc.CreateAttribute(string.Empty,
Noun.TEXT_ATTRIBUTE_NAME, string.Empty);
text.InnerText = _text;
// Add the attribute to the new Noun node.
noun.Attributes.Append(text);
// Add the Noun node to it's place in the master document.
node.AppendChild(noun);
}
此代码将由(This code would get called by a) Question
序列化时的对象,如果(object when it is serialized, if either the) Yes
要么(or) No
属性是(properties are) Noun
对象.我将在下面的部分中向您展示.该方法需要参考主要(objects. I’ll show you that in the section below. The method needs a reference to the main) XmlDocument
对象以创建新的节点和属性,并使用(object in order to create new nodes and attributes, and uses the) XmlNode
知道在文档中何处添加自身的参数.(parameter to know where in the document to add itself.) Noun.NodeName
是该类的公共静态属性,并返回该XML节点的XML节点名称.(is a public, static property of the class and returns the name of the XML node for the) Noun
.它是公共的,所以其他班级可以知道(. It’s public so other classes can know what the name of) Noun
节点也一样.(nodes are too.)
问题对象(Question Objects)
由于它们实现了与(Since they implement the same interface as) Noun
对象,它们具有一些相似之处.他们有一个字符串(objects, they share some similarities. They have a string) Text
属性,并可以使用传递给的相同参数进行序列化(property and can serialize themselves using the same parameters as passed to) Noun
对象.可以使用XML节点或属性值来构造它们.(objects. They can be constructed with either an XML node or with values for the properties.) Question
对象不同于(objects are different from) Noun
对象,但是,因为它们有(objects, though, in that they have) Yes
和(and) No
类型的属性(properties of type) IBorgElement
.(.)
public IBorgElement Yes {
get {return _yes;}
set {_yes = value;}
}
public IBorgElement No {
get {return _no;}
set {_no = value;}
}
这些属性由(These properties are used by the) App
类根据用户输入在决策树中移动到下一个问题或名词.(class to move through the decision tree to either the next question or a noun, depending on the user input.)
应用类别(App Class)
的(The) Question
和(and) Noun
对象只是用于数据的智能存储桶,活动功能有限.的(objects are just smart buckets for data, with limited active functionality. The) App
班级负责玩游戏.(class does the work of playing the game.)
它首先验证输入,并对要使用的数据库(Borg术语中的"集合")做出一些假设.它加载文件并传递第一个问题(第一个(It first validates input, and makes some assumptions about the database (“collective” in Borg terminology) you want to use. It loads the file and passes the first question (the first) XmlNode
根以下)到根的构造函数(below the root) to the constructor of the root) Question
.该构造函数解析(. That constructor parses the) Question
节点并通过(node and passes the) Yes
和(and) No
XmlNode
到(s to) Question
要么(or) Noun
构造函数,具体取决于节点的名称.递归构造问题,直到(constructors, depending on the name of the node. Questions are recursively constructed until) Noun
XML节点结束新对象的创建.(XML nodes end the new object creation.)
层次结构完全构建后,(Once the hierarchy is fully constructed, the) App
课问第一个问题.它通过将控制权传递给一个函数来寻求答案,该函数一直等到用户输入" Y"或" N":(class asks the first question. It solicits an answer by passing control to a function that waits until the user has entered a “Y” or a “N”:)
private static YesNoAnswer SolicitAnswer(string question,
ConsoleEx.Colour colour) {
string answer = string.Empty;
// Keep prompting until the user presses "y" or "n"
do {
ConsoleEx.Write(question + " (y/n) ", colour);
answer = ConsoleEx.ReadLine(ConsoleEx.Colour.Green); // User input in green.
} while (answer.ToLower() != "n" && answer.ToLower() != "y");
return (answer == "y" ? YesNoAnswer.Yes : YesNoAnswer.No);
}
回答问题后,(Once the question is answered,) App
检查是或否的类型(checks the type of the Yes or No) IBorgElement
目的.如果是(object. If it’s a) Question
对象,它将当前指针设置为新的(object, it sets the current pointer to the new) Question
对象并再次开始该过程.如果(object and starts the process again. If the) IBorgElement
对象是一个(object is a) Noun
对象,它将启动一组新的逻辑.(object, it launches into a new set of logic.)
的(The) App
类询问用户他们所想的名词是否是(class asks the user if the noun they were thinking of was the) Noun
在最后一个对象中.如果是这样,则游戏会在背面轻拍自己,并检查用户是否想再次玩.如果未正确猜出名词,则应用程序会询问用户选择的名词.然后,它提出一个问题,对旧名词回答"是",对新名词回答"否".这个问题是有意提出的,因为应用程序会将旧名词放在新问题的"否"侧,而将新名词放在新问题的"是"侧.如果新问题的措词不正确,则下次点击该问题时将切换答案.(in the final object. If it was, the game pats itself on the back and checks to see if the user wants to play again. If the noun was not guessed correctly, the application asks for the noun the user picked. It then solicits a question that answers Yes to the old noun, and No to the new noun. This question is solicited in a deliberate way, because the application is going to put the old noun on the No side of the new question and the new noun on the Yes side of the new question. If the new question is phrased incorrectly, the answers will be switched the next time the question is hit.)
一旦(Once the) App
班级知道新旧名词以及将它们区别开来的问题,它创建了一个新名词(class knows the old and new noun and the question that distinguishes them, it creates a new) Question
带有"是"和"否"的对象(object with the Yes and No) IBorgElement
节点分别设置为新名词和旧名词.它把新的(nodes set to the new and old nouns, respectively. It puts the new) Question
返回旧名词在对象层次结构中的位置,并保留数据.如果需要,请参考图2以获得图形化表示.(object back where the old noun was in the object hierarchy, and persists the data. Refer back to Image 2 for a graphical representation of this if you want.)
通过创建新的数据来保留数据(The data is persisted by creating a new) XmlDocument
具有虚拟根(“数据库"节点)的对象,并将其传递给根(object with a dummy root (“Database” node), and passing it to the root) Question
对象序列化例程.(object serialization routine.)
private static void SaveDatabase(IBorgElement data, string fileName) {
XmlDocument doc = new XmlDocument();
// Initialize the Xml document with the root node.
doc.AppendChild(doc.CreateNode(XmlNodeType.Element,
App.ROOT_NODE_NAME, string.Empty));
data.Serialize(doc, doc.SelectSingleNode(App.ROOT_NODE_NAME));
doc.Save(fileName);
}
App.ROOT_NODE_NAME
是根节点"数据库"的名称.的(is the name of the root node, “Database”. The) Question
对象将自身序列化为新对象(object serializes itself into the new) XmlDocument
在根节点上,并开始序列化(at the root node, and starts serializing the) Yes
和(and) No
属性.这将强制层次结构中的所有对象创建(properties. This will force all of the objects in the hierarchy to create) XmlNode
自己在主文档中,并用新的问题和答案完整地表示了知识树.(s for themselves in the master document, and gives a complete representation of the knowledge tree with the new question and answer.)
void Borg.IBorgElement.Serialize(XmlDocument doc, XmlNode node) {
XmlNode question = doc.CreateNode(XmlNodeType.Element,
Question.NodeName, string.Empty);
XmlAttribute text = doc.CreateAttribute(string.Empty,
Question.TEXT_ATTRIBUTE_NAME, string.Empty);
text.InnerText = _text;
// Append the Text attribute to the new Question node.
question.Attributes.Append(text);
XmlNode yesNode = doc.CreateNode(XmlNodeType.Element,
Question.YES_NODE_NAME, string.Empty);
XmlNode noNode = doc.CreateNode(XmlNodeType.Element,
Question.NO_NODE_NAME, string.Empty);
_yes.Serialize(doc, yesNode); // Serialize whatever's on the "Yes" side.
_no.Serialize(doc, noNode); // Serialize whatever's on the "No" side.
question.AppendChild(yesNode); // Append the Yes node to the Question node
question.AppendChild(noNode); // Append the No node to the Question node
// Append the Question node to where
// it goes in the master document.
node.AppendChild(question);
}
所结果的(The resulting) XmlDocument
被保存为旧版本,游戏会询问用户是否要再次玩.(gets saved over the old one, and the game asks if the user wants to play again.)
窗户装饰(Window Dressing)
我意识到并不是每个人都想从我的超级创意名词开始我的根本问题(“它是否还活着”).我还意识到,创建初始XML文档作为数据库是一个繁琐且容易出错的过程.的(I realize not everyone will want to start with my root question (“Is it alive”) with my super-creative nouns. I also realize that creating initial XML documents to serve as the database is a tedious and error prone process. The) App
类允许您通过使用某些命令行开关运行应用程序来创建自己的种子数据库.如果使用四个参数运行,则这些参数为(class allows you to create your own seed databases by running the application with some command line switches. If you run with four parameters, and those parameters are) /db:
,(,) /question:
,(,) /yes:
和(and) /no:
,您可以让它创建自己的根数据库.参数的顺序无关紧要.(, you can have it create your own root database. The order of the parameters does not matter.)
borg /db:"c:\birds.xml" /question:"Does it fly" /yes:"sparrow" /no:"penguin"
该命令行将在以下目录的根目录中创建一个新数据库(That command line will create a new database in the root of)*C:(c:*)叫(called)birds.xml(birds.xml),以指定的初始问题和名词作为种子,并将其打开以运行(如果成功创建).对不起示例中的动物偏见,但我的学位是动物学…(, seeded with the initial question and nouns as specified, and will open it for running (if it was created successfully). Sorry about the animal bias in the examples, but my degree is in Zoology…)
结论(Conclusion)
您会看到,Sith游戏使用的是相同类型的引擎,但是每个问题都有大量的指示. Sith游戏取代了"是"和"否”,提供了多种选择.正如我在此处所做的那样,将选择限制为"是"和"否"会吸引我的逻辑二进制方面,并减少所生成的数据关系中的歧义.并非巧合的是,它也更容易编码.(You can see that the Sith game exploits the same sort of engine, but with a larger number of directions to travel in from each question. Instead of “yes” and “no”, the Sith game allows for a multitude of options. Limiting the choices to “Yes” and “No” as I have done here appeals to my logical, binary side, and results in less ambiguity in the data relationships generated. Not coincidentally, it is also much easier to code.)
兴趣点(Points of Interest)
早些时候…(Back in the Day…)
早在互联网,USB和软盘出现之前,当只有有钱的孩子拥有300个波特调制解调器时(恐龙统治着地球),书呆子对应用程序共享机制的访问受到限制.我必须自己从杂志上输入原始游戏的源代码,然后才能将其保存到卡带驱动器中.在键入它们之前,您确实必须选择一些有趣的程序,因为这是花费大量时间来敲打应用程序的源代码并调试不可避免的错别字.这可能就是为什么我记得玩得这么清楚的原因.全部显示在32X16屏幕上.美好时光…(Back before the Internet, USB and diskettes, back when only rich kids had 300 baud modems (when dinosaurs ruled the earth), nerds had limited access to application sharing mechanisms. I had to type the source code for the original game myself from a magazine, before I could save it to my cassette drive. You really had to pick interesting programs before you typed them in, because it was a major investment of time to bang out the source code for an application, and debug the inevitable typos. It’s probably why I remember playing this game so clearly. All on a 32X16 screen. Good times…)
控制台颜色(Console Colour)
我最近一直在编写控制台应用程序,并且有兴趣使自己和其他人更轻松地为控制台编写体面的界面.我在此处放置了一些代码来进行颜色输出,并且正在编写一个用于控制台操作的综合库,该库应在2-3周内放在CodeProject上.一小部分代码包含在该项目的(I’ve been on a console app writing kick lately, and am interested in making it easier for myself and others to write decent interfaces for the console. I put some code in to do colour output here, and am writing a comprehensive library for console manipulation which should be on CodeProject in 2-3 weeks. A small subset of the code is included in this project in the) ConsoleEx
类.(class.)
序列化(Serialization)
我编写的每个对象都知道如何进行序列化和反序列化.我知道很多人讨厌这样做,并且更喜欢用(Each of the objects I’ve written know how to serialize and deserialize themselves. I know a lot of people who detest doing this, and prefer to decorate classes with the) [Serializable]
属性,然后让框架处理.不过,我尝试使用该框架自动进行序列化和反序列化,足以讨厌它.为了增加一些代码,您在处理上获得了难以置信的灵活性,因此我自己创建和解析XML文档.处理时不要马虎(attribute, and let the framework deal with this. I’ve tried to do serialization and deserialization automagically with the framework often enough to come to hate it, though. For the sake of a little extra code, you gain an incredible amount of flexibility in processing, so I create and parse XML documents myself. Don’t get sloppy when you’re handling) XmlNode
序列化代码中的s和属性等,然后开始将对象作为字符串数据摆弄.仅使用真实的XML对象,当某些用户开始将尖括号和"&“号插入其数据时,您将不会陷入困境.(s and attributes and the like in your [de]serialiation code and start fiddling with your objects as string data. Only use real XML objects, and you won’t be caught up when some user starts sticking angle brackets and ampersands into their data.)
此外,如果您正在解析的文档中存在错误,您可以抛出真正准确的上下文相关异常,以帮助人们诊断输入文件的问题.(Additionally, you can throw really accurate, context sensitive exceptions if there are errors in the document you’re parsing to help people diagnose their problem with input files.)
使用App.Config(Use of App.Config)
将运行时设置放入(Putting your run-time settings into)*应用配置(App.Config)*是众所周知的快捷方式,它允许您将少量的XML解析减少为更小的代码,并按如下方式读取设置:(is a well known shortcut, and allows you to reduce a small amount of XML parsing into an even smaller amount of code and read your settings like this:)
fileName =
System.Configuration.ConfigurationSettings.AppSettings.Get("LastDBPath");
显然,不应将其用于重写相同的设置.网上有很多人强烈建议不要这样做,例如应用程序文件夹((What it is not supposed to be used for, evidently, is re-writing those same settings. There are lots of people on the net who strongly advise against this, as the application folder (where the)*应用配置(App.Config)*出于安全目的,该应用程序可能无法对其进行写操作).该框架也对这个概念有偏见,因为它使您可以读取但不能写入该文件.(resides) may not be writable by the application for security purposes. The framework is prejudiced against this concept too, since it lets you read but not write to this file.) 我在该项目中专门编写了XML解析代码,以更新(I specifically wrote XML parsing code in this project to update the)*应用配置(App.Config)*在运行时违反最佳做法.我想将路径保存到成功加载的最后一个数据库,因此最终用户不必每次都在命令行上指定路径.他们只需要在更改数据库时指定它即可.(at run-time, going against the best practice. I wanted to save the path to the last database successfully loaded, so the end-user wouldn’t have to specify the path on the command line every time. They only have to specify it if they’re changing databases.) 如果要在程序执行之间保存一小部分数据,该怎么办?我猜是注册表,但是它充满了自身的安全风险. INI文件?我不回去了. XCOPY部署发生了什么?如果要在整个硬盘上复制配置文件,则无法执行此操作…(If you want to save a tiny bit of data between program executions, what are you supposed to do? Registry, I guess, but it’s fraught with its own security perils. INI files? I’m not going back there. What happened to XCOPY deployment? You can’t do it if you’re copying config files all over the hard drive…)
新的控制台模式(New Console Pattern)
在编写控制台应用程序时,我喜欢使用的策略是将较长的样板文本放入可执行文件中的嵌入式资源中,并在运行时将它们显示出来以显示它们.就像我在本项目中所做的那样,命令行开关参数和应用程序运行后的操作说明是此技术的最佳选择.文件(A strategy I like to use when I write console applications is to put long stretches of boilerplate text into embedded resources in the executable, and stream them out at run-time when I need to show them. Good candidates for this technique are command line switch parameters and instructions for what to do once the application is running, as I have done in this project. The files)*CLIText.txt(CLIText.txt)*和(and)*说明.txt(Instructions.txt)*都嵌入到可执行文件中,并在必要时通过调用以下函数显示:(are both embedded into the executable and are displayed when necessary by calling the following function:)
private static string ReadResource(string resource) {
Assembly me = Assembly.GetExecutingAssembly();
string res = me.GetName().Name + "." + resource;
StreamReader sr = new StreamReader(me.GetManifestResourceStream(res));
string data = sr.ReadToEnd();
sr.Close();
return data;
}
这样做避免了很多混乱和难以编辑的情况(Doing this avoids a lot of messy and hard-to-edit) System.Console.WriteLine()
在开始时调用(calls at the start of the) Main()
方法.(method.)
发布后(Post Build)
仅作为警告,该项目使用后构建步骤来复制(Just by way of warning, the project uses a post-build step to copy the)*Borg.xml(Borg.xml)*文件从项目文件夹放入运行时文件夹,因此,如果您在IDE中重复运行该应用程序,则添加到数据库的所有事实将在下一次编译时被覆盖.(file from the project folder into the run-time folder, so if you run the app repeatedly in the IDE, any facts you add to the database will get overwritten on the next compile.)
喇叭喇叭(Horn Honking)
最后但并非最不重要的一点是,在这里解析命令行参数时,我使用了我的"另一个命令行参数解析器”(YACLAP)库,您可以从中了解(Last but not least, to parse the command line parameters here, I use my Yet Another Command Line Argument Parser (YACLAP) library, which you can read about) 这里(here) .(.)
修订记录(Revision History)
- 2005年7月25日-初始修订.(July 25 2005 - Initial revision.)
许可
本文以及所有相关的源代码和文件均已获得The Code Project Open License (CPOL)的许可。
C# Win2K WinXP Win2003 Windows .NET1.1 Visual-Studio VS.NET2003 Dev 新闻 翻译