我有一堂表示表读数的课:
public class MeterReading
{
public double AccountId { get; set; }
public DateTime MeterReadingDateTime { get; set; }
public double MeterReadValue { get; set; }
}我还收集了一个名为MeterReadings的MeterReadingParseResult:
public class MeterReadingsParseResult : MeterReadingsBase
{
}这是从MeterReadingBase继承的。
public class MeterReadingsBase
{
private List meterReadings = new List();
public List MeterReadings { get => meterReadings; set => meterReadings = value; }
public int FailedParseReadings { get; set; }
}我所关注的主要方法是使用一个IFormFile (即CSV ),并在CSVHelper NuGet包的帮助下验证CSV文件内容,将其传递到D6类并将其添加到D6 MeterReadingParseResult集合中。CSVHelper代码通常是几行代码,但有些CSV文件可能包含需要加倍的单词,因此我不得不定制它,使验证符合我的目的。
public class MeterReadingsCsvProcessor
{
private readonly IMeterReadingsRepository _meterReadingsRepository;
private readonly IAccountsRepository _accountsRepository;
private MeterReadingsParseResult _parseResult;
public MeterReadingsCsvProcessor(
IMeterReadingsRepository meterReadingsRepository, IAccountsRepository accountsRepository)
{
_meterReadingsRepository = meterReadingsRepository;
_accountsRepository = accountsRepository;
_parseResult = new MeterReadingsParseResult();
}
public MeterReadingsParseResult CsvHandler(IFormFile file)
{
if (file == null)
throw new ArgumentNullException(nameof(file));
ParseCsv(file);
var accounts = _accountsRepository.GetAccounts();
return _parseResult;
}
private void ParseCsv(IFormFile file)
{
TextReader textReader = new StreamReader(file.OpenReadStream());
using (var csv = new CsvReader(textReader, CultureInfo.InvariantCulture))
{
csv.Read();
csv.ReadHeader();
CsvCustomErrorHandler customInt32Converter = new CsvCustomErrorHandler();
int lineNumber = 0;
while (csv.Read())
{
lineNumber++;
var meterReading = new MeterReading();
{
meterReading.AccountId = csv.GetField("AccountId");
meterReading.MeterReadingDateTime = DateTime.ParseExact
(csv.GetField("MeterReadingDateTime"),
"dd/MM/yyyy HH:mm", CultureInfo.InvariantCulture);
meterReading.MeterReadValue = csv.GetField("MeterReadValue", customInt32Converter);
if (meterReading.MeterReadValue < 1 || meterReading.MeterReadValue >= 100000)
{
_parseResult.FailedParseReadings++;
continue;
}
}
_parseResult.MeterReadings.Add(meterReading);
}
}
}
}我是否可以重构这段代码,以使它看起来更干净,或者在您的意见中,您认为我在我需要实现的功能方面做得最好吗?
发布于 2021-09-06 11:07:34
1.记录您的代码
虽然现在做起来有点无聊和无用,但在6个月后,您将再次阅读您的代码,并且需要一些时间才能记住这个类/字段/属性用于什么.
最低限度是用XML注释记录所有公共部分。您可以键入三个斜杠,///和Visual将插入以下内容:
///
///
/// 总之,您可以为要记录的项插入简短的说明。这在Visual中是可见的,并且可能非常有用。
属性一致性
在任何地方都可以使用没有私有字段的自动属性。除了一次,为了一份清单。为什么它不是另一个自动财产呢?
public List MeterReadings { get; set; } = new List();字段命名约定
在某种程度上,私有字段以小写字母开头。在其他地方,您可以用下划线开始您的私有字段。保持它的一致性,总是按照相同的惯例写它们。没有严格的规则,所以你只需要与自己保持一致(这并不总是容易的)或你的团队(这更难)。
在个人问题上,我不喜欢下划线,因为编译器使用它在后台生成一些支持字段,我不想干扰这一点。
4.未使用的变量
你有未使用的变量。这可能是一个良好的启动代码清理。你写的每一个变量都会花你一些时间去阅读和理解它的存在。如果没有使用变量,那么您就会浪费时间来理解为什么不使用它.
也许它在您的代码的其他部分中使用,但是由于您没有提到它,我假设它不会在其他地方使用。
_meterReadingsRepository:在构造函数中设置它,然后永远不再。是因为构造函数应该是这样的吗?因为它来自另一个你无法控制的公共接口?这是可能发生的,但请注意,这样您就可以知道为什么要浪费时间来创建一个不使用的变量。int lineNumber = 0;:您设置了这个值,并在每次迭代时增加它。非常好。但是你从来没有读过这个值,那有什么意义呢?调试问题?private MeterReadingsParseResult _parseResult;:您可以使用这个变量来存储csv解析结果,这很好。但你再也不用它了。所以你会记住它,也许是为了节省下一次调用解析方法时的时间?但你还是重新创造了它!所以变量是完全无用的。var accounts = _accountsRepository.GetAccounts();:这个简直就像魔法.这个电话该怎么做?因为你从不使用accounts变量。也许方法本身能为其他人做些重要的事情,但是没有办法知道.5.类型一致性
字段AccountId & MeterReadValue是类型为double,但是当您从csv解析它们时,它们应该是int。为什么?它们应该是整数还是双倍?
如果它们应该是双的,那么您就有一个bug,您应该将它们解析为double而不是int。
如果它们应该是int,则不需要使属性加倍。除非您有真正的理由,否则您应该添加一个注释来解释为什么它们是双重的,但被解析为int。
空检查
检查一次null。这很好。但是休息呢。您是否应该在构造函数中检查空值,在构造函数中接收两个值并将它们分配给您的私有字段?
7.方法的工作
CsvHandler到底在做什么?
这个方法值得吗?
另一个注释将出现在该方法的名称上。通常,你会选择一个动词来开始一个方法名,以便知道这个方法应该做什么.
以下是我应该做的:
public class MeterReading
{
public double AccountId { get; set; }
public DateTime MeterReadingDateTime { get; set; }
public double MeterReadValue { get; set; }
}
public class MeterReadingsBase
{
public List MeterReadings { get; set; } = new List();
public int FailedParseReadings { get; set; }
}
public class MeterReadingsParseResult : MeterReadingsBase
{
}
public class MeterReadingsCsvProcessor
{
///
/// Implements a new meter reading csv processor.
///
/// Unused parameter. Kept for retro compatibility
/// Unused parameter. Kept for retro compatibility
public MeterReadingsCsvProcessor(IMeterReadingsRepository meterReadingsRepository, IAccountsRepository accountsRepository)
{
}
public MeterReadingsParseResult ParseCsvFile(IFormFile file)
{
if (file == null)
throw new ArgumentNullException(nameof(file));
using (TextReader textReader = new StreamReader(file.OpenReadStream()))
using (CsvReader csv = new CsvReader(textReader, CultureInfo.InvariantCulture))
{
return ParseCsv(csv);
}
}
private MeterReadingsParseResult ParseCsv(CsvReader csv)
{
MeterReadingsParseResult parseResult = new MeterReadingsParseResult();
csv.Read();
csv.ReadHeader();
CsvCustomErrorHandler customInt32Converter = new CsvCustomErrorHandler();
while (csv.Read())
{
MeterReading reading = ReadOneValue(csv, customInt32Converter);
if (reading == null)
{
parseResult.FailedParseReadings++;
}
else
{
parseResult.MeterReadings.Add(reading);
}
}
return parseResult;
}
private MeterReading ReadOneValue(CsvReader csv, CsvCustomErrorHandler customInt32Converter)
{
MeterReading reading = new MeterReading()
{
AccountId = csv.GetField("AccountId"),
MeterReadingDateTime = DateTime.ParseExact(csv.GetField("MeterReadingDateTime"), "dd/MM/yyyy HH:mm", CultureInfo.InvariantCulture),
MeterReadValue = csv.GetField("MeterReadValue", customInt32Converter)
};
if (reading.MeterReadValue < 1 || reading.MeterReadValue >= 100000)
{
return null;
}
return reading;
}
}https://codereview.stackexchange.com/questions/267705
复制相似问题