Search code examples
qbfc

Generic Interfaces for ICustomerRetList and ICustomerRet - QBFC


Any QBFC developers out there? I'm using QBFC to pull multiple different types of objects out of Quickbooks: Customers, Items, Invoices, TaxCodes, etc. The data query code really only varies once you get to the Ret object so I'm trying to build some functions to abstract the process.

A typical repose object looks like

IReponseList
    IResponse
         RetList
             Ret

IResponseList and IResponse are both generic enough to work on all query response types. However, there doesn't appear to be a generic RetList and Ret Interface that I can use for the abstraction. I only have type-sepecific interfaces like ICustomerRetList, ISalesTaxCodeRetList, etc. I'd like to write the code independent of what TYPE of return list it is....

Is there an interface for RetList or Ret that I just can't seem to find?

Thanks


Solution

  • The interface IQBBase is the closest thing to what you're looking for. Most everything in QBFC is derived from IQBase, including all query types and all return types. Using IQBBase references and .NET generics it is possible to create a framework to deal with query results.

    Update: the iterator example below is now available as part of the Zombie library for QBFC, which you can grab from github.

    For example, here's a generic iterator that takes the RetList type and Ret type as parameters:

    /// <summary>
    /// This generic class simplifies and standardizes iteration syntax
    /// for QBFC lists.  Using this class we can use the foreach keyword
    /// to iterate across all items in a list.
    /// </summary>
    /// <typeparam name="L">The type of the list, for example IBillRetList</typeparam>
    /// <typeparam name="D">The type of the item, for example IBillRet</typeparam>
    public class QBFCIterator<L, D>:IEnumerable<D> where L : class, IQBBase
    {
    
        private L m_List;
    
        /// <summary>
        /// This constructor can be used for response list items or for sub-lists that are properties
        /// on other QBFC objects.
        /// </summary>
        /// <param name="lst">The sub-list</param>
        public QBFCIterator(IQBBase lst)
        {
            m_List = lst as L;
    
            if (m_List == null && lst != null)
            {
                throw new Exception("iterator type mismatch");
            }
        }
    
        public bool IsEmpty
        {
            get
            {
                if (m_List == null)
                {
                    return true;
                }
                else
                {
                    return Count == 0;
                }
            }
        }
    
        /// <summary>
        /// An efficient alternative to the Count() function
        /// </summary>
        public int EntityCount
        {
            get { return Count; }
        }
    
        public D GetFirstItem()
        {
            if (IsEmpty)
            {
                throw new Exception("Cannot retrieve item from empty list");
            }
            else
            {
                return GetAt(0);
            }
        }        
    
        #region Late-bound properties
        //
        // Since .NET requires that all methods invoked on a parameterized type
        // must compile based solely on interface constraints, we must use late
        // binding to access the count property and GetAt methods.  This may have 
        // an impact on performance and could conceivably cause run time errors 
        // with incorrect type parameters.
        //
        private int Count
        {
            get
            {
                if (m_List == null)
                {
                    return 0;
                }
                else
                {
                    Type t = m_List.GetType();
    
                    return (int)t.InvokeMember("Count",
                        System.Reflection.BindingFlags.GetProperty, null, m_List, null);
                }
            }
        }
    
        private D GetAt(int idx)
        {
            Type t = m_List.GetType();
    
            return (D)t.InvokeMember("GetAt", 
                System.Reflection.BindingFlags.InvokeMethod, null, m_List, new Object[] { idx });
        }
    
        #endregion
    
        #region IEnumerable<D> Members
    
        public IEnumerator<D> GetEnumerator()
        {
            if (m_List != null)
            {
                for (int idx = 0; idx < Count; idx++)
                {
                    yield return GetAt(idx);
                }
            }
        }
    
        #endregion
    
        #region IEnumerable Members
    
        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            if (m_List != null)
            {
                for (int idx = 0; idx < Count; idx++)
                {
                    yield return GetAt(idx);
                }
            }
        }
    
        #endregion
    }