Вызвать универсальный метод для свойств, которые известны во время выполнения - PullRequest
0 голосов
/ 11 марта 2019
public partial class ReturnHeader
{
        public int ReturnHeaderId { get; set; }
        public int CustomerId { get; set; }
        public string InvoiceNo { get; set; }
        public virtual Customer Customer { get; set; }
        public virtual ICollection<ReturnDetail> ReturnDetails { get; set; }
}

public void TraverseThroughClass<T> (T entity) where T : class
{
 try
 {
  var type = typeof(T);
  PropertyInfo[] props = type.GetProperties();
  foreach (PropertyInfo prop in props)
  {
   if (typeof(IEnumerable).IsAssignableFrom(prop.PropertyType))
  {

Эта проверка определяет, является ли свойство списком или нет.

Проблема 1: если true, приведите его в список или любую коллекцию. Что я хочу сделать, так это если свойство представляет собой коллекцию, приведенную к нему, и для каждого элемента в приведенной коллекции вызовите TraverseThroughClass

    /* Error casting into any collection*/
    //var propertiesValues = prop.GetValue(entity) as IList;
    var listType = GetCollectionItemType(prop.PropertyType);
    foreach (var listItem in propertiesValues)
    {

Проблема 2: для каждого элемента в коллекции вызывать TraverseThroughClass (T entity)

    }
  }
  else
  {
   Console.WriteLine("Prop Name : " + prop.Name + " Prop Value : " 
            + prop.GetValue(entity, null));
  }
}
 }
 catch (Exception e)
 {
  throw;
 }
}     

 public static Type GetCollectionItemType(Type collectionType)
 {
  var types = collectionType.GetInterfaces()
            .Where(x => x.IsGenericType
                && x.GetGenericTypeDefinition() == typeof(IEnumerable<>))
            .ToArray();
        return types.Length == 1 ? types[0].GetGenericArguments()[0] : null;
    }

1 Ответ

1 голос
/ 11 марта 2019

Похоже, вы пытаетесь разыграть ICollection как IList, что может или не может работать.Значение свойства во время выполнения может быть ICollection, которое не реализует IList.

Если значение этого свойства во время выполнения реализует IList, оно будет работать, но если нет, то не получится.

public virtual ICollection<ReturnDetail> ReturnDetails { get; set; }

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

Еще одна путаница заключается в том, что TraverseThroughClass принимаетпараметр entity, но в приведенном выше заявлении вы используете this для вызова свойства.Вы хотите вызвать свойство на entity?Это имело бы больше смысла.В противном случае происходит переключение - часть метода вызывает свойства entity, а часть вызывает свойство this, которое является экземпляром класса, в котором вызывается метод.

Чтобы прояснить это, я перемещаю TraverseThroughClass в его собственный статический класс и выполняю все операции с аргументом entity.Я также удалил GetCollectionItemType.Он вызывается, но результат вызова никогда не используется, поэтому не похоже, что он нам нужен.

Вот модифицированная версия вашего метода, перемещенная в его собственный класс.(Обратите внимание, что я не рассматриваю общую картину того, что пытается сделать это, просто пытаюсь обойти проблему в вашем вопросе.)

public static class Traversal
{
    public static void TraverseThroughClass<T>(T entity) where T : class
    {
        var type = typeof(T);
        PropertyInfo[] props = type.GetProperties();
        foreach (PropertyInfo prop in props)
        {
            if (typeof(IEnumerable).IsAssignableFrom(prop.PropertyType))
            {
                var propertiesValues = prop.GetValue(entity);

                // What if the property value is null?
                if (propertiesValues == null) continue;
                var collection = propertiesValues as IEnumerable;
                foreach (var listItem in collection)
                {
                    // I don't know what you want to do with these. 
                    // I'm just confirming that we're able to inspect them.
                    Debug.WriteLine("Success, we're iterating over the items!!"); 
                }
            }
            else
            {
                Debug.WriteLine("Prop Name : " + prop.Name + " Prop Value : "
                                  + prop.GetValue(entity, null));
            }
        }
    }
}

Это все еще оставляет детали, которые ваш метод будет проходить InvoiceNo, поскольку он реализует IEnumerable (это набор символов.) Если вы не хотите этого делать, вы можете специально исключить строки или более конкретно указать, какие типы вы делаете хотите пройти.

На этом этапе я могу выполнить этот код:

var returnHeader = new ReturnHeader
{
    ReturnDetails = new List<ReturnDetail>(
        new ReturnDetail[] { new ReturnDetail(), new ReturnDetail() }),
    InvoiceNo = "Invoice!"
};
Traversal.TraverseThroughClass(returnHeader);

... и обход будет повторяться как для символов в InvoiceNo, так и для элементов в ReturnDetails.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...