Search code examples
c#genericsentity-framework-coretypeof

Passing types to function in c#


I am using .net core 2.1 with entityframework core.

I have different models/entities/types defined in my project. e.g. Student, Class, Teacher.

I am getting the table data for these models to set in my cache.

At the moment, I am doing this;

string[] tablesToBeCached  = { "Student", "Class", "Teacher" };

foreach(var table in tablesToBeCached)
{
     cache.Set(key, GetTableData(dbContext, table));
}

and the function GetTableData() is defined as follows;

public IEnumerable<object> GetTableData(DBContext dbContext, string tableName)
{
      switch (tableName)
      {
          case "Student":
              return dbContext.Student;

          case "Class":
              return dbContext.Class;

          case "Teacher":
              return dbContext.Teacher;

          default:
              return null;
       }
  }

I want this code to be smart and short.

I tried following, but didn't work; (The error is 'x' is a variable but is used like a type)

List<object> entities = new List<object> { typeof(Student), typeof(Class), typeof(Teacher) };
entities.ForEach(x => GetTableData(x, dbContext));

public IEnumerable<object> GetTableData(object x, DBContext dbContext)
{
     return dbContext.Set<x>();
}

Can someone please help? Is it even possible in C#?


Solution

  • As someone pointed out in the comments, you should go with generics:

    cache.Set(key1, GetTableData<Student>(dbContext));
    cache.Set(key2, GetTableData<Class>(dbContext));
    cache.Set(key3, GetTableData<Teacher>(dbContext));
    
    
    public static IEnumerable<T> GetTableData<T> (DBContext dbContext)
    {
         return dbContext.Set<T>();
    }
    

    To avoid writing the same code (cache.Set) foreach entity, you can use reflection, but your entities should implement some kind of common interface or base class.

    For example, suppose your entities implement a common interface IEntity:

    interface IEntity {}
    
    class Student: IEntity {}
    
    class Teacher: IEntity {}
    

    then you can

    1 retrieve all the types that implement IEntity:

    var type = typeof(IEntity);
    var types = AppDomain.CurrentDomain.GetAssemblies()
        .SelectMany(s => s.GetTypes())
        .Where(p => type.IsAssignableFrom(p));
    

    2 call the GetTableData method in this way:

    MethodInfo method = GetType.GetMethod("GetTableData ");
    
    foreach (var entityType in types)
    {
        MethodInfo genericMethod = method.MakeGenericMethod(entityType);
        genericMethod.Invoke(this, null);
    }