0

I have this code using NPOI.
I'm trying to have an object that will be a either aHSSFWorkbook or a XSSFWorkbook depending on version of excel file.

It is possible to have an Type and past it to generic method in order to cast then return either HSSFWorkbook or XSSFWorkbook?

And also if it works, I will use GetWorkBook() in different method.

Please see my comment on constructor.

public class ExcelReader
{    
    public ExcelReader(filePath)
    {
        var isXls = Path.GetExtension(_filePath) == ".xls";
        // Is the following possible or is there any work around to get it work.
        var type = isXls ? HSSFWorkbook : XSSFWorkbook; 
        var workbook = GetWorkBook<type>();
        // Other init...
    }

    public T GetWorkBook<T>()
    {        
        return (T)Workbook.GetSheetAt();
    }
}
Lee Taylor
  • 7,761
  • 16
  • 33
  • 49
jmvtrinidad
  • 3,347
  • 3
  • 22
  • 42

3 Answers3

2

Generics need to have the Type at compile time. So, in normal way you cannot pass the Type dynamically to a generic method.

You can use this though (using reflection)

public ExcelReader(filePath)
{
    var isXls = Path.GetExtension(_filePath) == ".xls";
    var type = isXls ? typeof(HSSFWorkbook) : typeof(XSSFWorkbook); //get the type for the method

    var getWorkBook = this.GetType().GetMethod("GetWorkBook"); //get the generic method dynamically
    var genericGetWorkBook = getWorkBook.MakeGenericMethod(type); //use the type

    var workBook = genericGetWorkBook.Invoke(this, null); //call the method
    //Other init...
}

In your case, a simpler alternative would be to not use Generics

public ExcelReader(filePath)
{
    var isXls = Path.GetExtension(_filePath) == ".xls";
    var workBook = GetWorkBook(); //then cast or return object directly
    //Other init...
}

public object GetWorkBook()
{        
    return Workbook.GetSheetAt();
}

to cast to desired type

HSSFWorkbook hSSFWorkbook = null;
XSSFWorkbook xSSFWorkbook = null;
if (isXls)
    hSSFWorkbook = (HSSFWorkbook)workBook;
else
    xSSFWorkbook = (XSSFWorkbook)workBook;
Arghya C
  • 9,805
  • 2
  • 47
  • 66
  • I guess I will use most of the time the interface on Workbook that inherits `HSSFWorkbook` and `XSSFWorkbook` provided by NPOI and if I need method specifically to `XSSFWorkbook` I will cast the interface to `XSSFWorkbook`. By the way, Thanks! – jmvtrinidad Nov 06 '15 at 06:15
  • In that case your code will look very similar to the alternative approach. Just replace object with your interface. – Arghya C Nov 06 '15 at 06:23
  • It will need to cast in order to use the method of HSSF or XSSF. – jmvtrinidad Nov 06 '15 at 06:45
  • In the last part of my answer I have shown the casting part as well. – Arghya C Nov 06 '15 at 06:46
0

The ideal way is to have a base interface or class that both HSSFWorkbook and XSSFWorkbook inherit from. Then have

public IInterface GetWorkBook<T>()
{
     return Workbook.GetSheetAt();
}

and cast as required.

But if you don't have control on the classes you can use dynamic

public dynamic GetWorkBook<T>()
{
     return Workbook.GetSheetAt();
}

But do read up on dynamic before you go that route.

Shinva
  • 1,899
  • 18
  • 25
0

Why don't you simply change your implementation like this

    public ExcelReader(filePath)
{
    var isXls = Path.GetExtension(_filePath) == ".xls";

    if(typeof(isXls) == typeof(HSSFWorkbook))
          var workbook= GetWorkBook<HSSFWorkbook>();
    else if(typeof(isXls) == typeof(XSSFWorkbook))
          var workbook= GetWorkBook<XSSFWorkbook >();
    else{}
}

public T GetWorkBook<T>()
{  
    if(typeof(T) == typeof(HSSFWorkbook)     
     return (T)(object)(HSSFWorkbook)Workbook.GetSheetAt();
    return (T)(object)(XSSFWorkbook)Workbook.GetSheetAt();
}

Just use conditional statements based on your types.

Thabo
  • 1,492
  • 2
  • 18
  • 36