0

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);
Community
  • 1
  • 1
WereWolfBoy
  • 498
  • 1
  • 4
  • 23
  • 1
    I don't think that's possible, generics have to be known at compile time. Maybe through some form of reflection? – Barnstokkr Jun 10 '15 at 13:58

2 Answers2

1

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);
Community
  • 1
  • 1
Roman Starkov
  • 59,298
  • 38
  • 251
  • 324
  • 1
    There isn't such a function, which is too bad, because that would've been much easier. – WereWolfBoy Jun 11 '15 at 06:53
  • 1
    I edited the original post. After trying reflection I encountered another problem. Do you perhaps have any suggestions? – WereWolfBoy Jun 11 '15 at 08:30
  • 1
    @WereWolfBoy The problem now is probably that you're passing in "this" instead of "database". You need to pass in the object on which you're calling the method. Do read the documentation on Invoke; it should explain what goes where. – Roman Starkov Jun 11 '15 at 13:16
  • 1
    I did read more after I edited the post and also read that. Still gives me the same exception, though. Any other suggestions? – WereWolfBoy Jun 11 '15 at 13:34
  • 1
    @WereWolfBoy Why are your `parameters` "this" and "null"? The documentation states that if there are no parameters you should pass null. Also you're calling "LoadAll" instead of "ReadAll" in your modified code, does it also take no parameters? – Roman Starkov Jun 11 '15 at 14:34
  • 1
    The function was called LoadAll. I mistyped it as ReadAll before. The function does not have any parameters, that's why it has "this" and "null". I read somewhere that that was how it should be, don't remember where. I'll just make it null. That's probably the issue. – WereWolfBoy Jun 11 '15 at 14:45
  • 1
    That fixed it. If you edit your answer to include the complete answer I can accept it. – WereWolfBoy Jun 11 '15 at 14:52
1

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.

Stefan Steinegger
  • 63,782
  • 15
  • 129
  • 193
  • 1
    Thanks for your answer. I edited the original post. After trying reflection I encountered another problem. Do you perhaps have any suggestions? – WereWolfBoy Jun 11 '15 at 08:30