我需要将报告上传到其他不同的系统,该系统具有自己接受的报告的预定义结构。我们系统上的那些报告是根据用户选择的代码生成的。
用户不必关心他们要在报告上导出的列,他们只需要从UI中选择code
。我们的系统将参考code
生成并下载正确的CSV格式,并将其用作报告以上传到另一个系统。
CSV文件的标题和列数因用户选择的代码类型而异。
到目前为止我是怎么走的:
public ActionResult GetFileResult(string code)
{
var record = new Employee().GetEmployeeData(code);
var csvResult = GetCSVResult(code, record);
return csvResult;
}
private string GetCSVResult(string code, List<Employee> employees)
{
//How can i model here the GetCSVResult to convert
//the List of employees to CSV with refrence to code
//the value on the code will determine which format to used for the csv result.
}
在GetCSVResult
方法中,我可以使用多个if
或switch-case
语句来调用不同的方法,该方法具有自己的将列表转换为CSV的实现,但是至少有20种不同的方法CSV配置将导致多个if语句和很多方法。
public class Employee
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string DOB { get; set; }
public string StartDate { get; set; }
public string SSN { get; set; }
public bool PreviousEmployee { get; set; }
public List<Employee> GetEmployeeData(string code)
{
return new List<Employee>();
}
}
初始数据的格式具有以下结构。即从GetEmployeeData
FirstName | LastName | SSN | StartDate | DOB | PreviousEmployee
------------------------------------------------------------------------------------------
Jane | Smith | 111111121 | 01/03/2018 | 01/01/1983 | true
John | Smith | 111111111 | 01/01/2018 | 01/01/1970 | true
Jeff | Smith | 111111122 | 01/03/2018 | 01/01/1983 | false
现在,我必须使用不同的文件配置将这些数据转换为CSV(或一些转换为XML)文件。
例如示例:
某些格式可能是:
格式1:
FirstName,LastName,SSN,AppStartDate,AppDOB
Jane,Smith,111111121,01/03/2018,01/01/1983
John,Smith,111111111,01/01/2018,01/01/1970
Jeff,Smith,111111122,01/03/2018,01/01/1983
格式2:
EMP_FIRST_NAME,EMP_LAST_NAME,EMP_SSN,EMP_DOB,EMP_JOB_START_DATE,PREV_EMPLOYED_BY_EMPLOYER
Jane,Smith,111111121,01/03/2018,01/01/1983,Y
John,Smith,111111111,01/01/2018,01/01/1970,Y
Jeff,Smith,111111122,01/03/2018,01/01/1983,N
示例中的格式因Code
的类型而异。格式的结构由代码上的值定义。
那么,对于这种情况是否有一些通用的建议?或对某种模式有何建议?
要转换为CSV,我正在查看此线程
https://medium.com/@utterbbq/c-serializing-list-of-objects-to-csv-9dce02519f6b
答案 0 :(得分:0)
我不是CSV导出方面的专家,因此举一个您在GetCSVResult中尝试过的示例非常有用。但是,我的猜测是:
以防万一您误解了您的问题,您是否查看了这些链接? Fastest way to convert a list of objects to csv with each object values in a new line 和 Converting a generic list to a CSV string
现在,如果我不太了解,用户可以决定是否导出哪一列,并在需要时更改其名称。 因此,您可以拥有一个描述此类列的对象。例如:
public class ColumnCSV
{
public int OriginalColumnIndex{ get; set; }
public string Name { get; set; }
public bool ExpectedInCSV { get; set; }
}
然后,您将根据用户输入存储这些列的列表,并且可以轻松编写一个可爱的开关来处理基于列索引的导出。
答案 1 :(得分:0)
如果您不喜欢switch语句,并且有一些静态类型的键,则可能要使用以下内容:
static readonly string _divider = ",";
static readonly Dictionary<string, (string header, Func<Employee, string[]> employee)> _configurations
= new Dictionary<string, (string, Func<Employee, string[]>)>() {
["code1"] = ("FirstName,LastName,SSN,AppStartDate,AppDOB",
employee => new string[] {
employee.FirstName,
employee.LastName,
employee.SSN,
employee.StartDate,
employee.DOB }),
["code2"] = ("EMP_FIRST_NAME,EMP_LAST_NAME,EMP_SSN,EMP_DOB,EMP_JOB_START_DATE,PREV_EMPLOYED_BY_EMPLOYER",
employee => new string[] {
employee.FirstName,
employee.LastName,
employee.SSN,
employee.DOB,
employee.StartDate,
employee.PreviousEmployee ? "Y" : "N" })
//...
};
private string GetCSVResult( string code, List<Employee> employees )
=> _configurations[code].header
+ Environment.NewLine
+ employees.Select( e => _configurations[code]
.employee( e )
.Join( _divider ) )
.Join( Environment.NewLine );
我在这里使用此自定义扩展程序:
public static class Extensions {
public static string Join<T>( this IEnumerable<T> array, string divider = "," ) => string.Join( divider, array );
}
还要注意静态只读字典。您可能想使用并发或使用某种锁定机制来复制然后执行(不确定所有这些,TBH)。并且可以将其包装到某种类中以获取更清晰的视图(用法很干净,您可能要摆脱_divider,因为我们谈论的是 C SV)。
这不是最优的(无论是在内存上还是在cpu上),都没有针对相同结果和所有这些东西的缓存(而且我很确定string []结果不是连接的最佳方法,无论是否单击确定以连接字符串;还要注意,该字符串的通用版本。联接不是最佳的)。这完全取决于您,我希望您能从字典中得到灵感。
另一种方法是使用反射。这样做不是那么快又好。带有精神分裂症气味的杀死OOD的魔法。是的,您可以分配属性然后以某种方式执行它,但是无论如何它都是丑陋的(每种配置有几个属性或很多参数)。
还有其他几种方法可以使用纯IL或委托作为签名+ System.Linq.Expressions(包括反射,但仅在首次使用时使用)来“编译”此函式。
如果您想要一些真正干净的解决方案,则应考虑使用注入实现和用于结构描述的自定义脚本语言的抽象转换工厂,而不是对其进行硬编码。但为什么? 此代码将返回正确的CSV。希望会有所帮助。