1
Reply

How Do I instantiate an abstract class with generic type?

danieln4

danieln4

Nov 4 2009 4:07 PM
5.1k
Scenario: My goal is to load up an excel spreadsheet through a webform and the code will copy/update columns data into SQL.
Question: I have an abstract class public abstract class FileImporter<T> where T : class, new() which have couple of methods including one called public ImportResult ImportFile(string fileName). How do I instantiate or derive from this abstract class in another class to use the Importfile methods? Here are the entire code.

using System;
using System.Collections.Generic;
using System.Data.OleDb;
using System.IO;
using System.Linq;
using System.Reflection;

namespace SomeNameSpace
{
    /// <summary>
    /// This is deprecated.  Do not use.
    /// </summary>
    public class ColumnDefinition
    {
        /// <summary>
        /// Gets or sets the name of the column in the source file
        /// </summary>
        public string ColumnName { get; set; }

        /// <summary>
        /// Gets or sets the name of the destination property of the
        /// import object
        /// </summary>
        public string PropertyName { get; set; }

        /// <summary>
        /// Gets or sets whether the column must exist in the source document.
        /// </summary>
        public bool Required { get; set; }
    }

    public class ProcessItemEventArgs<T> : EventArgs
    {
        private ImportItemResult _result;
        private T _value;

        public ProcessItemEventArgs(T value, ImportItemResult result)
        {
            this._result = result;
            this._value = value;
        }

        public ImportItemResult Result
        {
            get { return _result; }
        }

        public T Item
        {
            get { return _value; }
        }
    }

    public delegate void ProcessItemHandler<T>(object sender, ProcessItemEventArgs<T> e);

    public abstract class FileImporter<T> where T : class, new()
    {

        private Dictionary<string, ColumnDefinition> _columns;
        private FileType fileType = FileType.Unknown;

        public event ProcessItemHandler<T> ProcessItem;

        public FileImporter(ColumnDefinition[] columns)
        {
            if (columns == null)
                throw new ArgumentNullException("columns");
            if (columns.Length == 0)
                throw new ArgumentException(String.Format(SR.InvalidArg_EmptyArray, "columns"));

            // Copy the column definitions into a dictionary
            _columns = columns.ToDictionary(x => x.ColumnName, StringComparer.OrdinalIgnoreCase);
        }

        protected virtual void OnProcessItem(ProcessItemEventArgs<T> e)
        {
            if (ProcessItem != null)
                ProcessItem(this, e);
        }


        public FileType FileType
        {
            get { return fileType; }
            set { fileType = value; }
        }

        protected bool IsColumnAvailable(string columnName)
        {
            return _columns.ContainsKey(columnName);
        }

        private FileType DetermineFileType(string filename)
        {
            FileType fileType = FileType.Unknown;

            FileInfo fi = new FileInfo(filename);
            switch (fi.Extension.ToUpperInvariant())
            {
                case ".XLS": fileType = FileType.Excel; break;
                case ".TXT": fileType = FileType.CSV; break;
                case ".CSV": fileType = FileType.CSV; break;
            }
            return fileType;
        }

        private string GetConnectionString(string filename, FileType fileType)
        {
            string cn = "";
            switch (fileType)
            {
                case FileType.CSV:
                    FileInfo fi = new FileInfo(filename);
                    cn = String.Format("Provider=Microsoft.Jet.OLEDB.4.0;Data Source={0};Extended Properties=\"text;HDR=Yes;FMT=Delimited\"", fi.DirectoryName);
                    break;
                case FileType.Excel:
                    cn = String.Format("Provider=Microsoft.Jet.OLEDB.4.0;Data Source={0};Extended Properties=\"Excel 8.0;HDR=Yes;IMEX=1\"", filename);
                    break;
                case FileType.Unknown:
                    fileType = DetermineFileType(filename);
                    if (fileType == FileType.Unknown)
                        throw new InvalidOperationException("Cannot determine filetype");
                    cn = GetConnectionString(filename, fileType);
                    break;
            }
            return cn;
        }

        /// <summary>
        /// Upload catalog item text blocks from an excel workbook
        /// </summary>
        /// <param name="fileName">The name of the file to import.</param>
        /// <returns>A <see cref="ImportResult"/> that contains the result of the import process.</returns>
        public ImportResult ImportFile(string fileName)
        {
            if (fileName == null)
                throw new ArgumentNullException("fileName");

            ImportResult result = new ImportResult();
            var itemResults = new List<ImportItemResult>();

            // load into oledb
            string _cnstr = GetConnectionString(fileName, this.FileType);

            using (OleDbConnection cn = new OleDbConnection(_cnstr))
            {
                cn.Open();
                OleDbCommand cmd = new OleDbCommand("SELECT * FROM [Sheet1$]", cn);

                using (OleDbDataReader rdr = cmd.ExecuteReader(System.Data.CommandBehavior.CloseConnection))
                {
                    try
                    {
                        Type objectType = typeof(T);
                        var props = new Dictionary<ColumnDefinition, PropertyInfo>();

                        var foundColumns = new Dictionary<string, ColumnDefinition>(StringComparer.OrdinalIgnoreCase);
                        for (int i = 0; i < rdr.FieldCount; i++)
                        {
                            var columnName = rdr.GetName(i);
                            ColumnDefinition col = null;
                            if (!_columns.TryGetValue(columnName, out col))
                            {
                                result.Success = false;
                                result.Message = String.Format("Unrecognized column ('{0}')", columnName);
                                return result;

                            }
                            foundColumns[col.ColumnName] = col;
                            props[col] = objectType.GetProperty(col.PropertyName);
                            _columns.Remove(columnName);
                        }

                        // Loop through remaining columns that were not found in the
                        // spreadsheet and determine if any were marked as required
                        string requiredColumns = "";
                        foreach (ColumnDefinition col in _columns.Values)
                        {
                            if (col.Required == true)
                                requiredColumns += ((requiredColumns.Length > 0 ? "," : "") + col.ColumnName);
                        }
                        if (requiredColumns.Length > 0)
                        {
                            result.Success = false;
                            result.Message = "Required columns " + requiredColumns + " missing";
                            return result;
                        }
                        _columns = foundColumns;

                        // Process records in spreadsheet

                        while (rdr.Read())
                        {
                            result.RecordCount++;

                            ImportItemResult itemResult = new ImportItemResult { RecordNumber = result.RecordCount };

                            T importObject = new T();

                            for (int i = 0; i < rdr.FieldCount; i++)
                            {
                                ColumnDefinition col = _columns[rdr.GetName(i)];
                                object value = rdr.GetValue(i);

                                PropertyInfo prop = props[col];
                                object convertedValue = Convert.ChangeType(value, prop.PropertyType);
                                prop.SetValue(importObject, convertedValue, null);
                            }

                            OnProcessItem(new ProcessItemEventArgs<T>(importObject, itemResult));
                            if (itemResult.Processed == true)
                            {
                                result.RecordsProcessed++;
                            }
                            else
                            {
                                itemResults.Add(itemResult);
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        result.Success = false;
                        result.Message = ex.Message;
                    }
                }
            }
            result.Items = itemResults.ToArray();
            return result;
        }
    }
}


Answers (1)