正在重新投射到派生类型
本文关键字:派生 类型 新投射 | 更新日期: 2023-09-27 17:59:51
我有一个问题,我不知道如何解决,我希望这里的人能有一些好的建议。
我正在分析文本文件,其中包含多个日志(每行一个日志)。格式如下:
Date Type Description
10/20 A LogTypeADescription
10/20 B LogTypeBDescription
10/20 C LogTypeCDescription
在这里,您可以看到有三种"类型"的日志(A、B和C)。根据日志的类型,我将以不同的方式解析"Description"字段。
我的问题是我应该如何设置数据结构?我想做这样的事情:
class Log
{
DateTime Date;
String Type;
String Description;
public Log(String line)
{
Parse(line);
}
}
class ALog : Log { }
class BLog : Log { }
class CLog : Log { }
现在,每个派生类都可以有自己独特的属性,这取决于"Description"字段的解析方式,并且它们仍将维护三个"核心"属性(Date、Type和Description)。
到目前为止一切都很好,只是我不知道我需要什么类型的(派生的)日志,直到我解析了日志文件中的行。当然,我可以解析这一行,然后计算出来,但我真的希望解析代码在"Log"构造函数中。我希望我能做这样的事情:
void Parse(String line)
{
String[] pieces = line.Split(' ');
this.Date = DateTime.Parse(pieces[0]);
this.Type = pieces[1];
this.Description = pieces[2];
if(this.Type == "A")
this = new ALog();
else if(this.Type == "B")
this = new BLog();
else if(this.Type == "C")
this = new CLog();
}
但不幸的是,我认为这是不可能的。我还没有尝试过,但我很确定会这样做:
Log l = new Log(line);
if(l.Type == "A") l = new ALog();
要么是非法的,要么破坏我第一次创建"日志"时所做的所有解析
有什么建议吗?
删除构造函数并将Parse更改为返回Log的静态。
static Log Parse(string line)
{
string[] tokens line.Split(' ');
var log = null;
if (tokens[1] == "A") log = new ALog();
else if (tokens[1] == "B") log = new BLog();
else log = new CLog();
log.Date = tokens[0];
log.Description = tokens[1];
return log;
}
我会将描述解析考虑到一个抽象方法中,该方法可以针对不同的描述类型进行重写。只有描述不同,所以只有这部分行解析需要分解到派生类型中包含的逻辑中。
using System;
class Log
{
DateTime Date;
String Type;
String Description;
public Log(String line)
{
String[] pieces = line.Split(' ');
this.Date = DateTime.Parse(pieces[0]);
this.Type = pieces[1];
LogParser parser = GetParser(this.Type);
this.Description = parser.Parse(pieces[2]);
}
static LogParser GetParser(string type)
{
switch (type)
{
case "A":
return new AParser();
case "B":
return new BParser();
case "C":
return new CParser();
default:
throw new NotSupportedException();
}
}
}
abstract class LogParser { public abstract string Parse(string line);}
class AParser : LogParser { public override string Parse(string line) { /* do parsing for A */ return string.Empty; } }
class BParser : LogParser { public override string Parse(string line) { /* do parsing for B */ return string.Empty; } }
class CParser : LogParser { public override string Parse(string line) { /* do parsing for C */ return string.Empty; } }
您可以像现在这样读取拆分中的行,然后读取"type"并调用Activator来创建从(可能是抽象的)基日志派生的一个具体类型,将拆分参数传递给构造函数,创建一个新的特定具体实例。
(此外,"Type"可能是派生类中的只读属性,因为您知道基于实例类型的值)。
当然,假设你不想避免反思。
另一个解决方案。放下你的OO锤子,拿起你的功能性锤子。
C#有字典和匿名函数。有一个函数字典,知道如何获取Log
和描述,并可以解析这些信息并将其放入Log
。那么你只需要parseDescription[logType](this, description)
。
这意味着您需要一个包含3个函数的字典,而不是3个新类。
在这个例子中差别并不大。但是,请考虑日志条目中是否有两个不同的字段,可能需要以多种方式进行解析。基于类的方法需要9个新类,而字典方法有2个字典,每个字典有3个函数。如果有3个,那么比较将是27个类与3个字典,每个字典有3个函数。
重新审视joncham和btilly的方法:
using System;
class Log
{
DateTime Date;
String Type;
String Description;
Dictionary<string,LogParser> logDictionary;
static Log()
{
logDictionary = new Dictionary<string,LogParser>;
logDictionary.Add("A",new AParser());
logDictionary.Add("B",new BParser());
logDictionary.Add("C",new CParser());
}
public Log(String line)
{
String[] pieces = line.Split(' ');
this.Date = DateTime.Parse(pieces[0]);
this.Type = pieces[1];
LogParser parser = GetParser(this.Type);
this.Description = parser.Parse(pieces[2]);
}
static LogParser GetParser(string type)
{
return logDictionary<string,LogParser>(type);
}
}
abstract class LogParser { public abstract string Parse(string line);}
class AParser : LogParser { public override string Parse(string line) { /* do parsing for A */ return string.Empty; } }
class BParser : LogParser { public override string Parse(string line) { /* do parsing for B */ return string.Empty; } }
class CParser : LogParser { public override string Parse(string line) { /* do parsing for C */ return string.Empty; } }