我想创建一个自定义属性,当在属性上进行修饰时,它将属性“设置”为该属性的值。在这种情况下,我正在读取一个excel文件,并希望将其值映射到属性。
using System;
namespace Excel.DataBind
{
[AttributeUsage(AttributeTargets.Property)]
public class ExcelDataBindAttribute : Attribute
{
private ExcelReader _excelReader;
public ExcelDataBindAttribute(string rangeAddress)
{
_excelReader = new ExcelReader();
_excelReader.GetExcelValue(rangeAddress);
// some code here to map it to the property it decorates...?
}
}
}
namespace Excel.Models
{
public class Model
{
[ExcelDataBind("A2")]
public string Value { get; set; }
}
}
我正在网上搜索以找到实现此目标的方法,但是反射是一种很好的方法。但是由于我是新手,所以我不确定这是否是最佳方法。有人可以指引我吗?
谢谢。
答案 0 :(得分:1)
首先,该属性(顾名思义)应仅以此装饰模型。单独的活页夹类应该比魔术更神奇。像这样:
using Excel.DataBind;
using System;
using System.Collections.Generic;
using System.Reflection;
namespace Excel.DataBind
{
public class ExcelDataBinder
{
public void DataBind(ExcelDocument doc, object target)
{
var lookup = new Dictionary<string, PropertyInfo>();
// loop through all properties of the target.
foreach(var prop in target.GetType().GetProperties())
{
// if the property has an decorator, store this.
var address = prop.GetCustomAttribute<ExcelDataBindAttribute>()?.Address;
if(!string.IsNullOrEmpty(address))
{
lookup[address] = prop;
}
}
// loop through all excel fields
foreach(var field in doc)
{
// if a mapping is defined
if(lookup.TryGetValue(field.Address, out var prop))
{
// use reflection to set the value.
prop.SetValue(target, field.Value);
}
}
}
}
[AttributeUsage(AttributeTargets.Property)]
public class ExcelDataBindAttribute : Attribute
{
public ExcelDataBindAttribute(string address) => Address = address;
public string Address { get; }
}
}
namespace Excel.Models
{
public class Model
{
[ExcelDataBind("A2")]
public string Value { get; set; }
}
}
这种方法也可以用于基于模型的Excel编写。
请注意,设置该值可能很棘手。您的ExcelDocument表示形式可能会使用与模型不同的类型(十进制与双精度等)。在这种情况下,您也必须进行转换。
另一句话:根据我的经验(在过去我曾写过类似的代码),在实际场景中,模型仅代表excel工作表标签的一行。比您需要带有标题行的内容,并且在列顺序上应该具有防御性。 (但是,您仍然需要属性来描述Excel真相与代码真相之间的关系。)