0

Я создаю собственное решение для обновления Entity Framework в отключенном сценарии. Можно было бы использовать много разных подходов, но я решил украсить свойства ICollection внутри моих объектов специальным атрибутом, чтобы я мог проверять состояние каждого объекта внутри этих коллекций. Вот пример объект с навигационным свойством:Как передать значение PropertyInfo в ICollection <T>, где T может быть любым классом

public class SomeEntity 
{ 
    public int TaskId{ get; set; } 
    public string Instruction { get; set; } 
    [EntityNavigationProperty] 
    public virtual ICollection<TaskExecutor> Executors { get; set; } 
} 

public class TaskExecutor 
{ 
    public int TaskExecutorId { get; set; } 
    public int TaskId { get; set; } 
    public virtual Task Task { get; set; } 
} 

public class EntityNavigationProperty : Attribute {} 

У меня есть универсальный метод Update, который я планирую использовать для обновления любого типа лица, которое будет гарантировать, что соответствующие лица также обновлены должным образом.

public void Update(TEntity entity) 
{ 
    PropertyInfo[] properties = entity.GetType().GetProperties(); 
    foreach (PropertyInfo pi in properties) 
    { 
     if (Attribute.IsDefined(pi, typeof(EntityNavigationProperty))) 
     { 
      foreach (//here I need to iterate through the ICollection object) 
      { 

      } 
     } 
    } 
} 

Теперь, предположим, я послав instnce задачи к выше обновление method.In линии 3, когда итератора приходит к Executors собственности, условие в строке 5 решает верно. Теперь мне нужно выполнить итерацию через свойство Executors и выполнить соответствующие задачи. В данном конкретном случае, в строке 6, я могу сказать:

foreach (var item in (pi.GetValue(entity) as ICollection<TaskExecutor>)) 

Но как я могу определить, что тип вместо Т в ICollection<T>?

+0

Я немного переформатировал ваш код и дал имена вашим классам. Проверьте, все ли в порядке – xanatos

ответ

1

Обычное решение:

foreach (object item in (IEnumerable)pi.GetValue(entity)) 
{ 
} 

, а затем внутри проверить тип item.

Обратите внимание, что по историческим причинам IEnumerable<T> основан на IEnumerable и ICollection<T> основан на IEnumerable<T> и так далее IEnumerable, но ICollection<T>не на основе ICollection.

В общем, если вы хотите, тип T из с IEnumerable<T> вы можете (взяты из https://stackoverflow.com/a/906513/613130):

// returns typeof(T) of an IEnumerable<T>, 
// or typeof(object) of an IEnumerable. 
public static Type GetGenericTOfIEnumerable(object o) 
{ 
    return o.GetType() 
      .GetInterfaces() 
      .Where(t => t.IsGenericType 
       && t.GetGenericTypeDefinition() == typeof(IEnumerable<>)) 
      .Select(t => t.GetGenericArguments()[0]) 
      .FirstOrDefault() ?? (o is IEnumerable ? typeof(object) : null); 
} 

к сведению, что с изменениями я введенными я создал несколько небольших побочных эффектов: а сбор НЕ на основе IEnumerable<T>, но только на IEnumerable вернет typeof(object). Коллекция основана на нескольких IEnumerable<T> будет возвращать только один один ... Например:

public class MyStupidClass : IEnumerable<int>, IEnumerable<long> 
{ 
} 

Но это вырожденный пример.