将属性动态转换为Type

时间:2016-12-19 09:11:12

标签: c# generics reflection

是否有可能简化这种逻辑,是否有通用的方法来做到这一点。 代码查找标记的属性并根据属性类型对其进行解析。 请建议一些优化此代码的方法,Product类的所有数据类型都是字符串,我得到的产品输入为xml直接将序列化数据转换为带有decimal的类,int,float不会给出正确的错误信息,如果有的话是在xml中抛出错误的项目列表,我们不知道哪一行导致了错误。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace TestSolution
{
    public interface ICustomParser
    {
        bool Parse(string input);
    }

    public class DecimalParserAttribute : Attribute, ICustomParser
    {
        public bool Parse(string input)
        {
            if (input == null) return false;

            decimal decimalValue;

            return decimal.TryParse(input, out decimalValue);
        }
    }

    public class intParserAttribute : Attribute, ICustomParser
    {
        public bool Parse(string input)
        {
            if (input == null) return false;

            int intValue;

            return int.TryParse(input, out intValue);
        }
    }

    public class Product
    {
        [DecimalParser]
        public string Weight { get; set; }

        [intParser]
        public string NoOfItems { get; set; }

        [intParser]
        public string GRodes { get; set; }

        [intParser]
        public string WRodes { get; set; }
    }

    class Program
    {
        static void Main(string[] args)
        {

            var sb = Validate(new Product() { NoOfItems = "1", GRodes = "4", Weight = "5", WRodes = "23" });

            Console.WriteLine(sb);
            sb = Validate(new Product() { NoOfItems = "1", GRodes = "4w", Weight = "5", WRodes = "23" });

            Console.WriteLine(sb);
            Console.ReadKey();
        }

        private static string Validate(Product product)
        {
            var sb = new StringBuilder();

            foreach (var property in product.GetType().GetProperties())
            {
                var value = Convert.ToString(property.GetValue(product, null));

                var sel = property.GetAttribute<ICustomParser>();

                if (sel == null) continue;

                var parserinstance = (ICustomParser)Activator.CreateInstance(sel.GetType());

                if (parserinstance.Parse(value)) continue;

                sb.AppendLine(string.Format("{0} Has invalid value", property.Name));
            }
            return sb.ToString();
        }
    }

    public static class Extensions
    {
        public static T GetAttribute<T>(this PropertyInfo property)
        {
            return (T)property.GetCustomAttributes(false).Where(s => s is T).FirstOrDefault();
        }
    }
}

1 个答案:

答案 0 :(得分:0)

如果你只有一种类型(Product),它可能是不值得的 - 只需明确地编写验证代码而不需要任何花哨的东西。但是,如果要检查多种类型(可能仅在运行时知道):

这取决于它需要多快。这种情况多久发生一次?如果它是周期性的,则没有大量的事情要做 - 主要的变化是直接投射解析器

var parserInstance = (ICustomParser)sel;

(已经 属性类型)

如果它是关键路径,那么你可以做一些 lot 来加强它,但你进入元编程领域 - 这实际上是大多数工具如序列化器和ORM所做的事情。减少运行时反射。如果你不熟悉在运行时黑客攻击IL,我建议你看一下像Sigil这样的工具(在nuget上可用),这很难弄错(或至少:告诉你什么你做错了)。从本质上讲,您可以检查数据结构,然后发出 IL,它与您在显式代码中完成所有内容的情况相匹配;例如,发出看起来有点像的IL:

static readonly DecimalParserAttribute _decimal = new DecimalParserAttribute();
public static void Validate(Product product) {
    var sb = new StringBuilder();
    if(!_decimal.Parse(product.Weight)) {
       sb.Append(...);
    }
    // ... etc
    ...,
}