2016-11-14 8 views
1

Datatableからジェネリック型のコレクションを生成する汎用メソッドを記述しました。私はさまざまな実装を探しましたが、多くのプロパティと多くのレコードを処理する場合、パフォーマンスの賢明さは非常に低いです。これは今のところかなり上手く行っています。リフレクトを使用してカスタム属性セットでプロパティを無視する

プロパティの上にカスタム属性(DataField)を追加してメソッドを改善しようとしましたが、これをプロパティに含めるだけで、列との一致をスキップしたり、カスタム名を指定することができますデータテーブルの列名と一致するプロパティの場合。

私はコードを見ましたが、私は本当に誇りに思っていませんでした。私はより良い実装をしたいと思います。誰も私にいくつかのヒントを与えることができますかそれは非常に感謝します。

どのくらい助けたかわからないコメントを含めるようにしました。ここで、ありがとうコードがされています。今、私たちはまた、我々は我々が無視したいすべてのプロパティをスキップし、一致する列名を持っていたオブジェクトに設定されたすべてのプロパティを持っている

private static void SetItemFromRow<T>(T item, DataRow row) where T : new() 
    { 
     // Get all properties with attributes. 
     PropertyInfo[] propWithAttributes = item.GetType().GetProperties().Where(x => Attribute.IsDefined 
      (x, typeof(DataField))).ToArray(); 

     foreach (DataColumn col in row.Table.Columns) 
     { 
      // Find property that matches the column name. 
      PropertyInfo p = item.GetType().GetProperty(col.ColumnName); 
      bool ignoreProperty = false; 

      if (p != null) 
      { 
       // If no attribute exists set the property value. Break out from the loop to go to the next column (Property). 
       if (!propWithAttributes.Contains(p)) 
       { 
        if (row[col] != DBNull.Value) 
        { 
         p.SetValue(item, row[col], null); 
         continue; 
        } 
       } 

       // If the property has a custom attribute then check if its ignore property is true. If so we break out from the loop and go to the next column (Property). 
       var attrs = p.GetCustomAttributes(typeof(DataField), false).ToArray() as DataField[]; ; 

       if (attrs != null) 
        foreach (var attr in attrs) 
        { 
         if (attr.Ignore) 
          ignoreProperty = true; 
        } 

       if (ignoreProperty) continue; 
      } 

      SetPropertyWithCustomName(item, propWithAttributes, row, col);  
     } 
    } 

。最後のステップでは、名前が定義されたDataField属性を持つプロパティを設定します。私は実際にそれを実行します(それがコンパイル検証)しませんでした

private static readonly Dictionary<Type, DataFieldProperty[]> _propsCache = new Dictionary<Type, DataFieldProperty[]>(); 
private static DataFieldProperty[] GetProperties(Type type) { 
    lock (_propsCache) { 
     if (!_propsCache.ContainsKey(type)) { 
      var result = new List<DataFieldProperty>(); 
      foreach (var prop in type.GetProperties(BindingFlags.Instance | BindingFlags.Public)) { 
       var attr = prop.GetCustomAttribute<DataField>(); 
       result.Add(new DataFieldProperty { 
        Name = attr?.Name ?? prop.Name, 
        Ignore = attr?.Ignore ?? false, 
        Property = prop 
       }); 
      } 
      _propsCache.Add(type, result.ToArray()); 
     } 
     return _propsCache[type]; 
    } 
} 

private class DataFieldProperty { 
    public string Name { get; set; } 
    public PropertyInfo Property { get; set; } 
    public bool Ignore { get; set; } 
} 

private static void SetItemFromRow<T>(T item, DataRow row) where T : new() { 
    // Get all properties with attributes. 
    var props = GetProperties(item.GetType()); 
    foreach (DataColumn col in row.Table.Columns) { 
     // Find property that matches the column name. 
     var p = props.FirstOrDefault(c => c.Name == col.ColumnName && !c.Ignore); 
     if (p != null) { 
      if (row[col] != DBNull.Value) { 
       p.Property.SetValue(item, row[col], null); 
      } 
     } 
    } 
} 

注:ここでは

  private static void SetPropertyWithCustomName<T>(T item, PropertyInfo[] propWithAttributes, DataRow row, DataColumn col) 
     where T : new() 
    { 

     foreach (var prop in propWithAttributes) 
     { 
      // Get the attributes for the property. 
      var attrs = prop.GetCustomAttributes(typeof(DataField), false).ToArray() as DataField[]; 
      bool match = false; 

      if (attrs != null) 
      { 
       foreach (var attr in attrs) 
       { 
        // Check if the column name matches the custom name on the property. 
        if (col.ColumnName == attr.Name) 
        { 
         var p = item.GetType().GetProperty(prop.Name); 
         if (row[col] != DBNull.Value) 
         { 
          p.SetValue(item, row[col], null); 
          match = true; 
          break; 
         } 
        } 
       } 

      if (match) break; 

      } 
     } 
    } 
+0

* nicier *を定義しますか?読みやすい?もっと早く?より多くのメモリが効率的ですか?いずれにしても、コードレビューは行われます(http://codereview.stackexchange.com/)。 – Sinatr

+0

もう少し読めると今のところできます。 –

+0

ありがとう、私はそれに "そこに"試してくれます。 –

答えて

0

はあなたのコードのビット読みやすくバージョン(私が正しく意図を理解している場合)です。

+0

時間を割いてくれてありがとう、私はそれを2番目にテストし、フィードバックを与えます。 –

+0

こんにちは、確かにそれほどコードが少なく、入れ子も少なくなっています。私はそれをテストし、完全に動作する、私はvs2015とC#6を持っていないので、小さな調整を行う必要があったが、うん、それは動作します!ありがとうございました ! –

+0

ようこそ。 GetPropertyの呼び出しもキャッシュされるので、大きなセットでは少し速くなるはずです。 – Evk

関連する問題