我正在编写一个C#应用程序,它读取语言X的源代码文件,并使用源文件中出现的类,方法等填充数据结构。
之后,使用我刚刚填充的这个数据结构,我可以调用这三个函数中的任何一个:
GenerateCS()
GenerateJava()
GenerateCPP()
基本上,它将语言X移植到这三种语言中的任何一种。
我的问题是,我如何构造这样的结构,使得我有一个类GenerateCode
作为基类,另一个生成函数从中派生出来?
我想每种语言的特定语法细节必须驻留在派生类本身中,但是我可以将哪些内容抽象到超类?
答案 0 :(得分:1)
怎么样:
public enum Language
{
CS,
Java,
CPP
}
public class CS: BaseClass { }
public class Java: BaseClass { }
public class Cpp: BaseClass { }
public class BaseClass
{
public abstract BaseClass ConvertTo(Language lang);
}
或
public class BaseClass
{
public abstract FromClass(BaseClass class, Language lang);
}
答案 1 :(得分:1)
我建议您从这样的结构开始:
public class MetaCode
{
private IList<Fields> fields;
private IList<Properties> properties;
private IList<Methods> methods;
public IList<Fields> Fields
{
get { return this.fields; }
}
public IList<Properties> Properties
{
get { return this.properties; }
}
public IList<Methods> Methods
{
get { return this.methods; }
}
// etc...
}
public interface ISourceReader
{
MetaCode ReadCode(string sourceCode);
}
public interface ISourceWriter
{
string WriteCode(MetaCode metaCode);
}
public class CodeConverter
{
private ISourceReader reader;
private ISourceWriter writer;
public CodeConverter(ISourceReader reader, ISourceWriter writer)
{
this.reader = reader;
this.writer = writer;
}
public string Convert(string sourceCode)
{
MetaCode metaCode = this.reader.ReadCode(sourceCode);
return this.writer.WriteCode(metaCode);
}
}
这只是伪代码,但您可以使接口遵循.NET框架中经常出现的StreamReader / StreamWriter模式。
接口允许整齐的扩展点,您可以在其中向应用程序添加新的源和目标编程语言。这种方法最好的事情是CodeConverter类对存在的不同编程语言一无所知。可以添加或删除新的,不需要更改。其他人甚至可以创建新的语言读者/编写者并使用它们而无需触及您的代码/编译程序集。
老实说,考虑到这一点,我不认为有很多功能可以抽象到基类。每种语言的细节都是如此具体,以至于基类很难正确完成。在任何情况下,我总是建议从接口开始,因为无论编程语言有多么模糊/不同,你总是可以创建一个实现。
也许你可以创建几个“辅助”基类,它们包含一些抽象功能,用于编程语言的不同通用样式:
public abstract class CLikeSourceReader : ISourceReader
{
public MetaCode ReadCode(string sourceCode)
{
// etc..
}
// etc..
}
public abstract class VisualBasicLikeSourceReader : ISourceReader
{
public MetaCode ReadCode(string sourceCode)
{
// etc..
}
// etc..
}
public abstract class AssemblyLanguageLikeSourceReader : ISourceReader
{
public MetaCode ReadCode(string sourceCode)
{
// etc..
}
// etc..
}
这样,在添加新语言时,您可以选择从这些预先存在的基类之一继承,如果它们都不合适,可以选择回退到接口。