Search code examples
c#entity-frameworkgenericsreflectionsystem.reflection

Make call to generic class nested function


I have Repository<T> where T is derrived form of BaseEntity class. Repository<T> has IQueryable<T> Table property. I need to make a call to FirstOrDefault method in the Table property.

till now i have got to list the Repositories, but stuck making call to the method using reflection.

private IEnumerable<object> GetEnumerableRepositoryOf<T>(params object[] constructorArgs) where T : class
        {
            List<object> objects = new List<object>();
            foreach (Type type in
                Assembly.GetAssembly(typeof(T)).GetTypes()
                .Where(myType => myType.IsClass && !myType.IsAbstract && myType.IsSubclassOf(typeof(T))))
            {                
                objects.Add(Activator.CreateInstance(typeof(Repository<>).MakeGenericType(type), constructorArgs));
            }
            return objects;
        }

var repoList = GetEnumerableRepositoryOf<BaseEntity>(constructorArgs);
foreach (var repo in repoList)
        {               
            // call FirstOrDefault() here
        }

Solution

  • So your list is Repository<X> where X is T, and the property Table is IQueryable<X>. As we are lacking type knowledge of X at compile time, reflection it is.

    So get the property with reflection by using the non-generic interface, then apply cast to T, and do your FirstOrDefault.

    Here's how you can do it:

    foreach (var repo in repoList)
    {
      var firstOrNull = 
        (repo.GetType().GetProperty("Table").GetValue(repo) as IQueryable)
          .Cast<BaseEntity>().FirstOrDefault();
    }
    

    If using entity framework (which does not support this kind of casting above):

    foreach (var repo in repoList)
    {
      var enumerator = 
        (repo.GetType().GetProperty("Table").GetValue(repo) as IEnumerable)
          .GetEnumerator();
    
      var firstOrNull = (BaseEntity) (enumerator.MoveNext() ? 
            enumerator.Current : default(BaseEntity));
    }