C # NET зацикливание на свойствах объекта, хранящихся в списке - PullRequest
0 голосов
/ 15 ноября 2018

В данный момент я работаю над функциональностью, которая включает в себя экспорт и импорт данных в файл Xlsx. Вот что я хочу сделать: я хочу иметь атрибут, который я могу поставить над таким свойством.

public class MyClass
{
   [XlsxColumn("Column 1")]
   public string myProperty1 { get; set; }
   public int myProperty2 { get; set; }
}

Пока у меня нет проблем, но затем я хочу "сохранить ссылки" на свойства, помеченные атрибутом XlsxColumn. Я использую отражение хранить данные о свойствах в списке

var propsList = MyClass.GetProperties().Where(
   prop => Attribute.IsDefined(prop, typeof(XlsxColumn)));

У меня есть список со всеми свойствами, помеченными XlsxColumn (только myProperty1 в этом примере).

РЕДАКТИРОВАТЬ: Проблема в том, что я не знаю, как перебирать свойства в MyClass, а только свойства с атрибутом XlsxColumn (поэтому все объекты PropertyInfo хранятся в переменной propsList), не прибегая к отражению для каждого объекта, сохраненного в файле Xlsx.

Я ограничен .NET 4.0.

Спасибо за ваше время.

Ответы [ 2 ]

0 голосов
/ 16 ноября 2018

MyClass.GetProperties() не работает, потому что вам нужно получить тип класса для вызова GetProperties метода .В противном случае вы вызываете статический метод GetProperties, определенный в классе MyClass.

var propsList = typeof(MyClass).GetProperties().Where(
                prop => prop.IsDefined(typeof(XlsxColumnAttribute), false)).ToList();

Если вы просто хотите, чтобы имена (IList<string>):

var propsList = typeof(Excel).GetProperties().Where(
                prop => prop.IsDefined(typeof(XlsxColumnAttribute), false))
                .Select(prop=> prop.Name)
                .ToList();

использовали .WhereВы должны включить System.Linq

0 голосов
/ 16 ноября 2018

Я должен сказать, что я не уверен, что это решение, которое вы ищете. Потому что я не мог разобрать, в чем твой вопрос. Ну, я пытался дать ответ столько, сколько я мог понять.

Я выбрал статический класс для CachingPropetyProvider, но вы можете перейти к классу экземпляра, использовать библиотеку внедрения зависимостей и использовать ее также как Singleton. Более того, я написал обширные комментарии, так что это как можно более понятно.

Давайте определим MyClass. Я тоже сознательно изменил это немного.

public class MyClass
{
    [XlsxColumn("Column 1")]
    public string MyProperty1 { get; set; }

    [XlsxColumn("Column 2")]
    public int MyProperty2 { get; set; }
}

Я также определил класс MetaInfo для хранения кэшированной информации.

public class MetaInfo {

    /// <summary>
    /// Immutable class for holding PropertyInfo and XlsxColumn info.
    /// </summary>
    /// <param name="info">PropertyInfo</param>
    /// <param name="attr">XlsxColumn</param>
    public MetaInfo(PropertyInfo info, XlsxColumn attr) {
        PropertyInfo = info;
        Attribute = attr;
    }

    /// <summary>
    /// PropertyInfo. You may want to access the value inside the property.
    /// </summary>
    public PropertyInfo PropertyInfo { get; }

    /// <summary>
    /// Attribute. You may want to access information hold inside the attribute.
    /// </summary>
    public XlsxColumn Attribute { get; }
}

И, наконец, главный парень. Этот парень отвечает за предоставление всех данных о занятиях

public class CachingPropProvider {

/// <summary>
/// Holds the meta information for each type.
/// </summary>
private static readonly ConcurrentDictionary<Type, List<MetaInfo>> TypeCache;

/// <summary>
/// Static constructor is guaranteed to run only once.
/// </summary>
static CachingPropProvider() {
    //Initialize the cache.
    TypeCache = new ConcurrentDictionary<Type, List<MetaInfo>>();
}

/// <summary>
/// Gets the MetaInfo for the given type. Since We use ConcurrentDictionary it is thread safe.
/// </summary>
/// <typeparam name="T">Type parameter</typeparam>
public static IEnumerable<MetaInfo> GetCachedStuff<T>() {
    //If Type exists in the TypeCache, return the cached value
    return TypeCache.GetOrAdd(typeof(T),Factory);
}

/// <summary>
/// Factory method to use to extract MetaInfo when Cache is not hit.
/// </summary>
/// <param name="type">Type to extract info from</param>
/// <returns>A list of MetaInfo. An empty List, if no property has XlsxColumn attrbiute</returns>
private static List<MetaInfo> Factory(Type @type) {
    //If Type does not exist in the TypeCahce runs Extractor
    //Method to extract metainfo for the given type
    return @type.GetProperties().Aggregate(new List<MetaInfo>(), Extractor);
}

/// <summary>
/// Extracts MetaInfo from the given property info then saves it into the list.
/// </summary>
/// <param name="seedList">List to save metainfo into</param>
/// <param name="propertyInfo">PropertyInfo to try to extract info from</param>
/// <returns>List of MetaInfo</returns>
private static List<MetaInfo> Extractor(List<MetaInfo> seedList,PropertyInfo propertyInfo) {
    //Gets Attribute
    var customattribute = propertyInfo.GetCustomAttribute<XlsxColumn>();

    //If custom attribute is not null, it means it is defined
    if (customattribute != null)
    {
        //Extract then add it into seed list
        seedList.Add(new MetaInfo(propertyInfo, customattribute));
    }
    //Return :)
    return seedList;
}

}

Наконец, давайте посмотрим, как использовать решение. На самом деле это довольно просто.

//Has 2 values inside
var info = CachingPropProvider.GetCachedStuff<MyClass>();
...