通用解析器设计

时间:2011-11-03 12:00:05

标签: c# oop design-patterns

我已经实现了解析员工详细信息的功能,同样我将需要解析销售,客户等,因为我需要再创建2个功能。代码将在所有函数中重复,唯一的区别是

  • 函数的返回类型
  • 实例化适当的对象
  • 要阅读的单元格

有没有办法将重复代码移动到一个类并配置它以便重用它?

public List<Employee> ParseEmployee(string filePath)
        {
            Application _excelApp = null;
            Workbooks workBooks = null;
            Workbook workBook = null;
            Sheets wSheets = null;
            Worksheet wSheet = null;
            Range xlRange = null;
            Range xlRowRange = null;
            Range xlcolRange = null;
            List<Employee> empLst= new List<Employee>();
            try
            {

                _excelApp = new Application();

                workBooks = _excelApp.Workbooks;
                workBook = workBooks.Open(filePath, Type.Missing, Type.Missing, Type.Missing, Type.Missing,
                                                        Type.Missing, Type.Missing, Type.Missing, Type.Missing,
                                                        Type.Missing, Type.Missing, Type.Missing, Type.Missing,
                                                        Type.Missing, Type.Missing);


                wSheets = (Sheets)workBook.Sheets;
                wSheet = (Worksheet)wSheets.get_Item(1);


                xlRange = wSheet.UsedRange;
                xlRowRange  = xlRange.Rows;
                xlcolRange = xlRange.Columns;

                int rowCount = xlRowRange.Count;
                int colCount = xlcolRange.Count;

                for (int i = 2; i <= rowCount; i++)
                {   

                    Range cell1 = xlRange.Cells[i, 1] as Range;
                    Range cell2 = xlRange.Cells[i, 2] as Range;
                    Range cell3 = xlRange.Cells[i, 3] as Range;

                    object val1 = cell1.Value2;
                    object val2 = cell2.Value2;
                    object val3 = cell3.Value2;

                    Employee emp = new Employee();

                    emp.FirstName = val1.ToString();
                    emp.LastName = val2.ToString();
                    emp.EmpID = val3.ToString();

                    empLst.Add(emp);

                    Marshal.ReleaseComObject(cell1);
                    Marshal.ReleaseComObject(cell2);
                    Marshal.ReleaseComObject(cell3);
                }

            }
            catch (Exception exp)
            {
            }
            finally
            {
                GC.Collect();
                GC.WaitForPendingFinalizers();

                workBook.Close(false, Type.Missing, Type.Missing);                
                _excelApp.Quit();


                Marshal.ReleaseComObject(xlRowRange);
                Marshal.ReleaseComObject(xlRange);
                Marshal.ReleaseComObject(xlcolRange);
                Marshal.ReleaseComObject(wSheet);
                Marshal.ReleaseComObject(wSheets);                
                Marshal.ReleaseComObject(workBook);
                Marshal.ReleaseComObject(workBooks);

                Marshal.ReleaseComObject(_excelApp);

            }


            return empLst;
        }

3 个答案:

答案 0 :(得分:1)

我认为visitor pattern可能非常合适。您可以修改上面的函数以包含名为visitor的参数。然后修改for循环以将相关数据传递给访问者对象:

for (int i = 2; i <= rowCount; i++)
{
    visitor.VisitRow(xlRange.Cells, i);
} 

visitor.VisitRow()函数将提取所需的数据,并在内部保留对提取的对象的引用。您将拥有不同的访客,一个是雇主,一个是销售,客户等。

最后,你会写这样的东西:

Visitor employerVisitor = new EmployerVisitor();
Visitor salesVisitor = new SalesVisitor();

Parse("workbook-employers.xls", employerVisitor);
Parse("workbook-sales.xls", salesVisitor);

List<Employee> employers = employerVisitor.GetData();
List<Sale> sales = salesVisitor.GetData();

答案 1 :(得分:0)

您可以通过以下方式从泛型类中公开它:

public class ObjectParser<T>
{
    public List<T> ParseObject(string filePath, Func<Range, T> f)       
    {       
        Application _excelApp = null;       
        Workbooks workBooks = null;       
        Workbook workBook = null;       
        Sheets wSheets = null;       
        Worksheet wSheet = null;       
        Range xlRange = null;       
        Range xlRowRange = null;       
        Range xlcolRange = null;       
        List<T> lst= new List<T>();       
        try       
        {       

            _excelApp = new Application();       

            workBooks = _excelApp.Workbooks;       
            workBook = workBooks.Open(filePath, Type.Missing, Type.Missing, Type.Missing, Type.Missing,       
                                                    Type.Missing, Type.Missing, Type.Missing, Type.Missing,       
                                                    Type.Missing, Type.Missing, Type.Missing, Type.Missing,       
                                                    Type.Missing, Type.Missing);       


            wSheets = (Sheets)workBook.Sheets;       
            wSheet = (Worksheet)wSheets.get_Item(1);       


            xlRange = wSheet.UsedRange;       
            xlRowRange  = xlRange.Rows;       
            xlcolRange = xlRange.Columns;       

            int rowCount = xlRowRange.Count;       
            int colCount = xlcolRange.Count;       

            for (int i = 2; i <= rowCount; i++)       
            {          
               lst.Add(f(xlRange));
            }       

        }       
        catch (Exception exp)       
        {       
        }       
        finally       
        {       
            GC.Collect();       
            GC.WaitForPendingFinalizers();       

            workBook.Close(false, Type.Missing, Type.Missing);                       
            _excelApp.Quit();       


            Marshal.ReleaseComObject(xlRowRange);       
            Marshal.ReleaseComObject(xlRange);       
            Marshal.ReleaseComObject(xlcolRange);       
            Marshal.ReleaseComObject(wSheet);       
            Marshal.ReleaseComObject(wSheets);                       
            Marshal.ReleaseComObject(workBook);       
            Marshal.ReleaseComObject(workBooks);       

            Marshal.ReleaseComObject(_excelApp);       

        }       


        return lst;       
    }       
}

要使用它:

ObjectParser<Employee> op = new ObjectParser<Employee>()
op.Parse(filepath, r => /* insert code to handle Employee here */)

我担心的是,一些Marshall.ReleaseComObject()调用被推送到传入的lambda,这使得它有点重量级。您能否告诉我们更多关于Employee与其他类型之间使用哪些单元格的差异?

答案 2 :(得分:0)

我已将我的代码重新计算为类似

的代码
   class ExcelParser : IDisposable
{
    bool disposed = false;
    Application _excelApp = null;
    Workbooks workBooks = null;
    Workbook workBook = null;
    Sheets wSheets = null;
    Worksheet wSheet = null;
    Range xlRange = null;
    Range xlRowRange = null;
    Range xlcolRange = null;

    public bool Load(string filePath)
    {
        bool bFlag = true;
        try
        {
            _excelApp = new Application();

            workBooks = _excelApp.Workbooks;
            workBook = workBooks.Open(filePath, Type.Missing, Type.Missing, Type.Missing, Type.Missing,
                                                    Type.Missing, Type.Missing, Type.Missing, Type.Missing,
                                                    Type.Missing, Type.Missing, Type.Missing, Type.Missing,
                                                    Type.Missing, Type.Missing);

            wSheets = (Sheets)workBook.Sheets;
            wSheet = (Worksheet)wSheets.get_Item(1);

            xlRange = wSheet.UsedRange;
            xlRowRange = xlRange.Rows;
            xlcolRange = xlRange.Columns;
        }
        catch (Exception exp)
        {
            throw;
        }

        return bFlag;
    }

    public int GetRowCount()
    {
        int rowCount = 0;
        if(xlRowRange != null)
            rowCount = xlRowRange.Count;

        return rowCount;
    }

    public string GetValue(int rowIndex, int colIndex)
    {
        string value = "";
        Range cell = null;
        try
        {
            cell = xlRange.Cells[rowIndex, colIndex] as Range;
            object val = cell.Value2;
            value = val.ToString();                
        }
        catch (Exception exp)
        {
        }
        finally
        {
            Marshal.ReleaseComObject(cell);
        }

        return value;
    }

    protected virtual void Dispose(bool disposing)
    {
        if (!this.disposed)
        { // don't dispose more than once
            if (disposing)
            {
                // disposing==true means you're not in the finalizer, so
                // you can reference other objects here
                GC.Collect();
                GC.WaitForPendingFinalizers();

                if (workBook != null)
                    workBook.Close(false, Type.Missing, Type.Missing);

                if (_excelApp != null)
                    _excelApp.Quit();

                if (xlRowRange != null)
                    Marshal.ReleaseComObject(xlRowRange);
                if (xlRange != null)
                    Marshal.ReleaseComObject(xlRange);
                if (xlcolRange != null)
                    Marshal.ReleaseComObject(xlcolRange);
                if (wSheet != null)
                    Marshal.ReleaseComObject(wSheet);
                if (wSheets != null)
                    Marshal.ReleaseComObject(wSheets);
                if (workBook != null)
                    Marshal.ReleaseComObject(workBook);
                if (workBooks != null)
                    Marshal.ReleaseComObject(workBooks);
                if (_excelApp != null)
                    Marshal.ReleaseComObject(_excelApp);
            }              

        }
        this.disposed = true;
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);            
    }

    ~ExcelParser()
    {
        Dispose(false);
    }
}

,调用代码如下所示

public List<Employee> Handle(string filePath)
        {
            List<Employee> empLst = new List<Employee>();

            ExcelParser exlParser = new ExcelParser();
            try
            {
                if (exlParser.Load(filePath))
                {
                    int rowCount = exlParser.GetRowCount();
                    for (int i = 2; i <= rowCount; i++)
                    {
                        Employee emp = new Employee();

                        emp.FirstName = exlParser.GetValue(i, 1);
                        emp.LastName  = exlParser.GetValue(i, 2);
                        emp.EmpID     = exlParser.GetValue(i, 3);

                        empLst.Add(emp);                       
                    }
                }
            }
            catch (Exception exp)
            {
            }
            finally
            {
                exlParser.Dispose();
            }

            return empLst;
        }

所以现在我可以在我想使用的任何地方重用解析器。请评论这是否正确