簡體   English   中英

使用反射忽略具有自定義屬性集的屬性

[英]Ignore properties with custom attribute set, using reflection

我編寫了一個泛型方法,從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);    
        }
    }

現在我們在具有匹配列名的對象上設置了所有屬性,我們也跳過了我們想要忽略的所有屬性。 最后一步是設置具有定義了Name的DataField屬性的屬性。

            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;

            }
        }
    }

這是一個更易讀的代碼版本(如果我理解正確的意圖):

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);
            }
        }
    }
}

請注意,我實際上沒有運行它(但驗證它編譯)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM