如何将自定义属性值绑定到属性?

时间:2020-02-13 12:25:10

标签: c#

我想创建一个自定义属性,当在属性上进行修饰时,它将属性“设置”为该属性的值。在这种情况下,我正在读取一个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; }
    }
}

我正在网上搜索以找到实现此目标的方法,但是反射是一种很好的方法。但是由于我是新手,所以我不确定这是否是最佳方法。有人可以指引我吗?

谢谢。

1 个答案:

答案 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真相与代码真相之间的关系。)