3

I'm trying to avoid having to write a large number of switch/case (or if/else) statements in one area of my code. Take the following method:

async internal static Task UndeleteAsync(JObject item, string tableName)
{
    switch (tableName)
    {
        case "QuoteTask":
               var obj = item.ToObject<QuoteTask>();
               var deletedObj = (await MobileService.GetTable<QuoteTask>().IncludeDeleted().Where(x => x.Id == obj.Id).ToListAsync()).FirstOrDefault();
               await MobileService.GetTable<QuoteTask>().UndeleteAsync(deletedObj);                        
        break;
               //Only 26 more tables to go...                
    }        
}

This works well, but I have a ton of tables, I'm not too familiar with generics but I thought maybe something like this would work:

async internal static Task UndeleteAsync<T>(JObject item)
{            
    var obj = item.ToObject<T>();
    var deletedObj = (await MobileService.GetTable<T>().IncludeDeleted().Where(x => (x as BaseObject).Id == (obj as BaseObject).Id).ToListAsync()).FirstOrDefault();
    await MobileService.GetTable<T>().UndeleteAsync(deletedObj);
}

This seems to be ok, it doesn't give me any compiler errors, but my issue is I can't seem to call it:

Type tableType = Type.GetType(operation.Table.TableName);
await AzureMobileServices.UndeleteAsync<tableType>(operation.Item);

I get the error "tableType" is a variable but is used like a 'type'.

So I guess generics have to be identified at compile time. So I would have to have a massive switch/case or if/else statement to figure out the type anyway.

Can someone direct me towards an elegant way to do this? Or is there no way around it?

Matt F
  • 204
  • 1
  • 11
  • Is there a reason you cannot pass the type at compile time? You can have multiple layers of generics if you need to – maccettura Jun 23 '17 at 16:38
  • What about inheritance? Can you create a common base type? If not, you could still try interfaces. And you can combine both with generics. Don't worry, it's easier as you might think. ;-) – Tobias Knauss Jun 23 '17 at 16:41
  • Passing the type at compile time would require me to know the type, and I'll need a switch/case for 27 tables, which is what I'm trying to avoid. – Matt F Jun 23 '17 at 16:41
  • 1
    This is likely a bigger design issue. What does the entry point look like? (i.e the method that wraps your last code block in your post) – maccettura Jun 23 '17 at 16:43
  • The entry point is an exception of a HttpRequest based on Azure App Services. It's a class that handles sync conflicts, so in the error, I do not get the actual type of the object. Only a JObject, and a tableName, which is a string. – Matt F Jun 23 '17 at 16:47
  • The problem with inheritance is if I convert the JObject to my BaseObject class, all other properties get lost. Then there is no way to convert the BaseObject into the specific object I need in order to insert into my table. – Matt F Jun 23 '17 at 16:52
  • 1
    @JonSkeet posted a [pretty good answer](https://stackoverflow.com/questions/325156/calling-generic-method-with-a-type-argument-known-only-at-execution-time) about this that might be able to help – maccettura Jun 23 '17 at 16:52
  • 1
    @MattF actually you should be able to get what you need from that answer I linked. – maccettura Jun 23 '17 at 16:57
  • Thank you @maccettura! This worked perfectly, although now I have another issue within the actual method, in that because I don't have a concrete type, I can't query the row I'm looking for with LINQ. But that's another issue, this one is solved. Want to re-port your comment as an answer? – Matt F Jun 23 '17 at 17:35
  • 1
    @MattF your question has already been closed because it is a duplicate, besides JonSkeet did all the work I just found it. Thanks though! – maccettura Jun 23 '17 at 17:36

0 Answers0