Get type programmatically and use it as a typeparam

1.1k views Asked by At

What I want to do is read everything that is in my lex.db database. Preferably by paged with pages of a pre-defined size. I have done the following:

DbInstance database = GetDatabase();
var tables = database.AllTables();
foreach (var table in tables)
{
    string str = table.ToString();
    str = str.Replace("Lex.Db.DbTable`1[", string.Empty);
    str = str.Replace("]", string.Empty);
    Type t = Type.GetType(str);

    if (t != null)
    {
    var columns = database.ReadAll<t>();
    //handle all columns
    }
}

The problem is that the function ReadAll has a typeparam. I assumed I could use the type as the typeparam, since it represents the class that I want to results of.

However I get the error:

"The type or namespace name 't' could not be found (are you missing a using directive or an assembly reference?)".

So how can I make it so that the actual type will be used as the typeparam instead of the letter 't'?

I'm creating a windows universal app for windows 8.1 and windows phone 8.1

EDIT:

Based on the suggestions that romkyns and Stefan Steinegger gave I tried using reflection. I now have the following code:

DbInstance database = DbInstance.GetInstance();

System.Type thisType = database.GetType();
TypeInfo thisTypeInfo = thisType.GetTypeInfo();
MethodInfo method = thisTypeInfo.GetDeclaredMethod("LoadAll");

var tables = database.AllTables();
foreach (var table in tables)
{
    string str = table.ToString();
    str = str.Replace("Lex.Db.DbTable`1[", string.Empty);
    str = str.Replace("]", string.Empty);
    Type t = Type.GetType(str);
    if (t != null)
    {
        MethodInfo generic = method.MakeGenericMethod(t);
        object[] parameters = { this, null };
        var columns = generic.Invoke(database, parameters);

        if (columns != null)
        {
            //handle columns
        }
    }
}

This works up to the point that the invoke method is called. At that point the following exception occurs:

An exception of type 'System.Reflection.TargetException' occurred in mscorlib.dll but was not handled in user code

Additional information: Object does not match target type.

Any clues on how to resolve this?

EDIT II:

The invoke method had to be called as:

var columns = generic.Invoke(database, null);
2

There are 2 answers

7
Roman Starkov On BEST ANSWER

The only way to make a call like that is to use reflection. The <T> is supposed to be known at compile time, but in your case it isn't, therefore you cannot do it like that.

Such APIs often come with an overload that takes a Type directly though. Check if yours has it. It might look something like this:

database.ReadAll(t);
1
Stefan Steinegger On

You have to use reflection. It is not possible to combine runtime types with compile time types in another way:

(might be wrong, just by heart it looks something like this:)

var dbInstanceType = typeof(DbInstance);
var readAllMethod = dbInstanceType.GetMethod("ReadAll");
var typedReadAllMethod = readAllMethod.BuildGenericMethod(t);
var result = typedReadAllMethod.Invoke(dbInstanceType);

Normally you have a non-generic method to pass in runtime types, because generics do not make sense in this case.