5

I have a Method which accepts a Generic T class

  public void CreateTables<T>()
   {
    string name = typeof(T).Name;

    var fields = typeof(T).GetProperties().Select(t => new { key = 
    t.Name.ToLower(CultureInfo.InvariantCulture), value = 
    SqLiteUtility.GetSQLiteTypeString(t.PropertyType) })
      .ToDictionary(t => t.key, t => 
          t.value);

    CreateTable(name, fields);
    }

   and 

    public void PushData<T>() where T : EntityData
   {
    var data = _context.Set<T>().Where(p => p.Deleted == false).ToList();
   }

I have more than 50 types for which this method needs to be called Like this

CreateTables<Class1>();
PushData<Class1>();

Although I can do like this, but i prefer to create maybe array of Types and use for loop to call this method

Something like this

   Type[] types=new Types[]{typeof(Class1),typeof(Class2)}

   foreach(var type in types)
   {
    //call create table method
      CreateTables<type>(); - - this doesnt work as "type" is a variable 
                                used as a type 

   }

Is there a way around this? that can also save me a lot of code and refactor things effectively?

EDIT1:

From the answers , indeed Parameters like CreateTables(Type T) can work, however for the second method above, is there also a possibility?

In the second it's important that T is mentioned of type EntityData as the code in the method depends on it.

Mandar Jogalekar
  • 3,199
  • 7
  • 44
  • 85
  • Do those classes have anything in common that would allow you to find them using reflection? – Timothy Groote Nov 09 '17 at 12:20
  • When you step into the world of reflection you're generally not able to easily step back out. To invoke that method generically you will have to use reflection to invoke it. – Lasse V. Karlsen Nov 09 '17 at 12:20
  • 2
    So write `CreateTables(Type)`, and have `CreateTables` call `CreateTables(typeof(T))`. You're not *using* the fact that `T` is available at compile time at all, so you're not losing any expressiveness. – Jeroen Mostert Nov 09 '17 at 12:20
  • @TimothyGroote they all inherit from same class. – Mandar Jogalekar Nov 09 '17 at 12:25
  • Possible duplicate of [Generics in C#, using type of a variable as parameter](https://stackoverflow.com/questions/2107845/generics-in-c-using-type-of-a-variable-as-parameter) – SᴇM Nov 09 '17 at 12:28
  • 2
    Whats wrong with this people now days, asking 7-10 years old question and everybody like: "oooh, let me answer and get votes, I will not even search if question has answer or not."? – SᴇM Nov 09 '17 at 12:36

3 Answers3

9

Essentially you're trying to go from reflection to generics and back to reflection.

Since the method in question simply steps back into reflection a better method is to create an overload taking a type, like this:

public void CreateTables<T>()
{
    CreateTables(typeof(T));
}

public void CreateTables(Type tableType)
{
    string name = tableType.Name;

    var fields = tableType.GetProperties().Select(t => new
        {
            key = t.Name.ToLower(CultureInfo.InvariantCulture),
            value = SqLiteUtility.GetSQLiteTypeString(t.PropertyType)
        })
        .ToDictionary(
            t => t.key,
            t => t.value);

    CreateTable(name, fields);
}

This way you can still call it with a specific type, generics-wise, or you can call it from your loop by simply passing the type object.


Having said all that, if you cannot change the method to take a Type object, here's how you need to invoke it using reflection:

var m = GetType().GetMethod("CreateTables").MakeGenericMethod(new Type[] { type });
m.Invoke(this, null);

Note! This assumes you only have one such method available, that it is public, etc.

Lasse V. Karlsen
  • 380,855
  • 102
  • 628
  • 825
  • I have also edited the question with another similar method, does it also fit into this scenario? would be very useful indeed – Mandar Jogalekar Nov 09 '17 at 12:33
  • @MandarJogalekar yes, the last remark on this answer is what I commented on your comment to my answer. Just create a generic method via reflection and invoke it – Jcl Nov 09 '17 at 12:37
7

You can make something like this:

public void CreateTables<T>()
{
  CreateTables(typeof(T));
}

public void CreateTables(Type type)
{
  string name = type.Name;

  var fields = type.GetProperties().Select(
      t => new { 
         key = t.Name.ToLower(CultureInfo.InvariantCulture), 
         value = SqLiteUtility.GetSQLiteTypeString(t.PropertyType) 
      }).ToDictionary(
         t => t.key, 
         t => t.value);

  CreateTable(name, fields);
}

And then:

Type[] types=new Types[]{typeof(Class1),typeof(Class2)}

foreach(var type in types)
{
    CreateTables(type);
}

If you only use that method in the loop, you can remove the generic version, it'd not be needed at all

Jcl
  • 27,696
  • 5
  • 61
  • 92
  • certainly works. there is also another method(Edited original question) , which not sure fits into this, but great answer :) – Mandar Jogalekar Nov 09 '17 at 12:33
  • You could use reflection to create a generic method definition and invoke it. Quite ugly, but it works – Jcl Nov 09 '17 at 12:35
4

Try this:

public void CreateTables<T>() => CreateTables(typeof(T));

public void CreateTables(Type type)
{        
    string name = type.Name;

    var fields = type.GetProperties()
      .Select(t => new { 
          key = t.Name.ToLower(CultureInfo.InvariantCulture), 
          value = SqLiteUtility.GetSQLiteTypeString(t.PropertyType) })
      .ToDictionary(t => t.key, t => t.value);

    CreateTable(name, fields);
 }

Or even this:

public void CreateTables(IEnumerable<Type> types) {
    if(types != null) {
        foreach(Type type in types) {
            CreateTables(type);
        }
    }
}
Roman Koliada
  • 4,286
  • 2
  • 30
  • 59