0

I have a generic method to deal with importing various object types from Quickbooks.

public ActionConfirmation<int> Import<TEntity>(List<TEntity> lstEntityModifiedSinceLastSync, FinancialsSyncJobQueue currentJobQEntry, FinancialsSyncSession session, 
    FinancialsIntegrationContext financialsIntegrationContext) 
    where TEntity : class, IEntity, IAuditStamps, IFinancials, new()

Today I use a switch statement to invoke the above generic method with the correct type:

switch (enumDataElement)
{
    case DataElement.Account:
        {
            //Parse QB query response and convert to Stratus Chart of Accounts object list
            var lstAccountsModifiedSinceLastSync = QuickbooksChartOfAccounts.ParseQueryResponse(response, session);

            importResult = importService.Import<FinancialsChartOfAccount>(lstAccountsModifiedSinceLastSync, 
                currentJobQEntry, session, financialsIntegrationContext);

            break;
        }
    case DataElement.Item:
        {
            var lstItemsModifiedSinceLastSync = QuickbooksItem.ParseQueryResponse(response, session);

            importResult = importService.Import<Item>(lstItemsModifiedSinceLastSync, 
                currentJobQEntry, session, financialsIntegrationContext);

            break;
        }
        etc...
}

I'd like to clean this up a little, pull the importService.Import call out of the switch statement and put it at the end and do something like:

Type entityType = lstItemsModifiedSinceLastSync.FirstOrDefault().GetType();
importResult = importService.Import<entityType>(lstItemsModifiedSinceLastSync, 
    currentJobQEntry, session, financialsIntegrationContext);

But I can't seem to get that to work. Error is: The type or namespace could not be found...

crichavin
  • 4,672
  • 10
  • 50
  • 95
  • @EdPlunkett - Thank you for pointing me to that question/answer. I didn't see that the way I was searching for existing questions. – crichavin Jul 06 '16 at 19:39

1 Answers1

1

This won't work because type arguments are the actual names of types, resolved at compile time by the compiler. It needs the name of a type, but you're giving it the name of a variable instead.

Type entityType = lstItemsModifiedSinceLastSync.FirstOrDefault().GetType();
importResult = importService.Import<entityType>(lstItemsModifiedSinceLastSync, 
    currentJobQEntry, session, financialsIntegrationContext);

It is possible to call generic methods with type parameters determined at runtime, but you have to use reflection. For your case, something like this (not tested):

//  Get the entity type by reflection too, so we don't have to worry about
//  crashing on an empty list. 
Type entityType = lstItemsModifiedSinceLastSync.GetType().GenericTypeArguments.First();

MethodInfo method = importService.GetType().GetMethod("Import");
MethodInfo generic = method.MakeGenericMethod(entityType);

generic.Invoke(importService, new object[] { 
        lstItemsModifiedSinceLastSync, 
        currentJobQEntry, 
        session, 
        financialsIntegrationContext
    });

It's up to you whether you consider this more or less ugly than what you've got already. And if Import has overloads, you'll have to rummage through a list of MethodInfo objects to find the right one.

By the way, you could also use type information on lstItemsModifiedSinceLastSync to get its type parameter, instead of relying on there being an item in the list. If there's not, FirstOrDefault() will return null and that line will throw an exception.

Community
  • 1
  • 1
  • thanks for the pointer on getting the type of the list...but I thought that'd return a type of List instead of just Type, which I didn't think would work. I'll give that a shot. – crichavin Jul 06 '16 at 19:43
  • @ChadRichardson It will return the type of List -- you'll have to look at `lstItemsModifiedSinceLastSync.GetType().GenericTypeArguments.First()`. Since List is List, you can safely assume there's exactly one of them. – 15ee8f99-57ff-4f92-890c-b56153 Jul 06 '16 at 19:47
  • gotcha, thanks for the clarity. – crichavin Jul 06 '16 at 20:45