在父类中使用自定义属性设置子属性

时间:2015-06-23 12:41:29

标签: c#

我正在创建一个Log Parsing工具,即将CSV文件解析为从根类派生的各个类。但是,由于存在数百种不同类型的日志,因此定义各个类并在每个类中设置各自的属性需要很长时间。我注意到的事情是它几乎都是完全相同的东西,并想看看是否有办法加快速度并做一些LINQ to DB如何做事情并添加一些逻辑来自动设置基于属性信息的属性。

以下是我正在使用的一个示例,以及有关如何运作的想法。

class Program
{
    static void Main(string[] args)
    {
        Dictionary<string, string> dictionary = new Dictionary<string, string>
        {
            {"key", "Stack Overflow"},
            {"item1", "Test"},
            {"item2", "Sample"},
            {"item3", "3"}
        };

        Example example = new Example(dictionary);
        Console.WriteLine(example.LogKey);  //Stack Overflow
        Console.WriteLine(example.Item1);   //Test
        Console.WriteLine(example.Item2);   //
        Console.WriteLine(example.Item3);   //3
        Console.ReadKey();
    }
}

[AttributeUsage(AttributeTargets.Property)]
class LogItem : Attribute
{
    public LogItem(string key)
    {
        Key = key;
    }

    public string Key { get; private set; }
    public bool Ignore { get; set; }
}

class Log
{
    public Log(Dictionary<string, string> items)
    {
        Dictionary = items;
    }

    public Dictionary<string, string> Dictionary { get; private set; }

    [LogItem("key")]
    public string LogKey { get; set; }
}

class Example : Log
{
    public Example(Dictionary<string, string> items) : base(items)
    {
    }

    [LogItem("item1")]
    public string Item1 { get; set; }

    [LogItem("item2", Ignore = true)]
    public string Item2 { get; set; }

    [LogItem("item3")]
    public int Item3 { get; set; }
}

遗憾的是,我的所有数据都以字符串形式出现,所以获取属性的类型并将字符串转换为该属性是个好主意。这个问题现在不重要,因为我可以自己做。

有没有人知道如何制作这样的作品?如果可能的话,可以在父类中完成这样的操作,以允许子类使用属性Ignore == true来设置属性。

2 个答案:

答案 0 :(得分:0)

你见过LinqToCSV吗?您可以为每种类型的日志创建类,添加继承等,并使用属性描述列。

这里是您的代码变得多么简单的一个例子。

IEnumerable<ManualInputFormat> MapFileToRows(Stream input)
{
    var csvDescriptor = new CsvFileDescription
                            {
                                SeparatorChar = ',',
                                FirstLineHasColumnNames = true
                            };

    var context = new CsvContext();
    return context.Read<InputFormat>(new StreamReader(input), csvDescriptor);
}

其中InputFormat是您的目标属性POCO

http://www.codeproject.com/Articles/25133/LINQ-to-CSV-library

答案 1 :(得分:0)

在研究了LINQ to CSV的工作原理之后,我能够提出以下建议。

static void ExtractData(Log log)
{
    List<PropertyInfo> propertyInfos =
        log.GetType()
            .GetProperties()
            .Where(
                p => p.GetCustomAttributes(typeof (LogItem), true).Any(logItem => !((LogItem) logItem).Ignore))
            .ToList();

    foreach (var propertyInfo in propertyInfos)
    {
        LogItem logItem = (LogItem)propertyInfo.GetCustomAttributes(typeof(LogItem), true).First();

        if(!log.Dictionary.ContainsKey(logItem.Key))
            continue;

        TypeConverter typeConverter = TypeDescriptor.GetConverter(propertyInfo.PropertyType);
        MethodInfo parseNumberMethod = propertyInfo.PropertyType.GetMethod("Parse",
            new[] { typeof(String), typeof(NumberStyles), typeof(IFormatProvider) });
        MethodInfo parseExactMethod = propertyInfo.PropertyType.GetMethod("ParseExact",
            new[] { typeof(string), typeof(string), typeof(IFormatProvider) });

        Object objValue = null;

        if (typeConverter.CanConvertFrom(typeof(string)))
        {
            objValue = typeConverter.ConvertFromString(null, CultureInfo.CurrentCulture, log.Dictionary[logItem.Key]);
            Debug.WriteLine("TypeConverter - " + propertyInfo.Name);
        }
        else if (parseExactMethod != null)
        {
            objValue =
                parseExactMethod.Invoke(
                    propertyInfo.PropertyType,
                    new Object[]
                        {
                            log.Dictionary[logItem.Key],
                            logItem.OutputFormat,
                            CultureInfo.CurrentCulture
                        });
        }
        else if (parseNumberMethod != null)
        {
            objValue =
                parseNumberMethod.Invoke(
                    propertyInfo.PropertyType,
                    new Object[]
                        {
                            log.Dictionary[logItem.Key],
                            logItem.NumberStyles,
                            CultureInfo.CurrentCulture
                        });
        }
        else
        {
            objValue = log.Dictionary[logItem.Key];
        }

        PropertyInfo goodPropertyInfo = propertyInfo.DeclaringType.GetProperty(propertyInfo.Name);
        goodPropertyInfo.SetValue(log, objValue, null);
    }
}