2015-06-23 64 views
0

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

下面是我正在使用的一个示例,以及关于应该如何工作的一个想法。

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

+0

你可以使用反射来设置属性,但是如果你已经有'Dictionary',为什么你真的需要属性? 'Example'类的用法是什么?为什么不保留'Dictionary'?而且,对于属性来说,它并不是很清楚(对我?)。 CSV - >字典,完美,无需上课。 – Sinatr

回答

0

目标属性我能想出寻找到LINQ到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); 
    } 
} 
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

OP想要CSV。并且链接唯一的答案不是很受欢迎(考虑从那里发布重要的关键部分)。 – Sinatr

+0

虽然我同意链接唯一的答案。这个页面已经有相当长的一段时间了(2008),并且我在生产中多次使用这个解决方案。如果页面被删除,那么可能会有更好的解决方案,因此这个答案已经过时。 – Mark