locked
Maintaining Business Objects -Thoughts RRS feed

  • Question

  • User1238834067 posted

    We are using below class(TypeInterceptor) in one of our project to create the instance of business objects.

    To Create any business object, we are using the below code

    ++++++++++

    BLayer.TestBO objTestBO;

    this.objTestBO = TypeInterceptor.CreateObject<BLayer.TestBO>();

    +++++++++++

    I think using this kind of creational pattern makes the application not scalable as the same instance will be shared among all the concurrent users.Is it correct?

    Is there any better way to abstract the creation and maintaining instance of business objects

    Class code:

    namespace Microsoft.IT.RelationshipManagement.Internal.CISF.Infrastructure
    {
        using System;
        using System.Linq;
        using System.Text;
        using System.Reflection;
        using System.Collections;
        using System.CodeDom.Compiler;
        using System.Collections.Generic;
        using Microsoft.CSharp;
        using System.IO;

        public class TypeInterceptor
        {
            private static Hashtable _htTypes = null;
            private static Hashtable _htTypesSynchronized = null;

               static TypeInterceptor()
            {
                _htTypes = new Hashtable();
                _htTypes.Clear();
                _htTypesSynchronized = Hashtable.Synchronized(_htTypes);
            }

            public static T CreateObject<T>() where T : new()
            {
                T targetObject = default(T);
                Type typeGenerated = null;

                string strCallingAssembly = Assembly.GetAssembly(typeof(T)).CodeBase.ToString().Replace("file:///", string.Empty);

                if (!_htTypes.Contains(typeof(T).ToString()))
                {
                    string str = BuildClass<T>();
                    typeGenerated = GenerateType<T>(str, strCallingAssembly);
                    _htTypes.Add(typeof(T).ToString(), typeGenerated);
                }
                else
                {
                    typeGenerated = (Type)_htTypes[typeof(T).ToString()];
                }

                targetObject = (T)Activator.CreateInstance(typeGenerated);
                return targetObject;
            }

    Tuesday, February 2, 2010 2:19 AM

Answers

  • User-952121411 posted

    There might be better approaches if we really want to maintain the single instance using singleton or abstract the instance using factory pattern?
     

    Agreed.  If your overall goal is to make sure that only one instance of the class is being used, then the Singleton Design can be implemented in a much more streamlined manner in its simplest form.  In a nutshell, all that needs to be done is check if an instance exists or not and either return the existing instance or a new one.  The additional code in your example seems unnecessary, however it is always difficult to see the entire picture just from a little code and a few descriptions. Below is some additional information:

    Exploring the Singleton Design Pattern:

    http://msdn.microsoft.com/en-us/library/ee817670.aspx

    As far as exception handling goes, I agree it is nice to know what the offending method was.  But this is easy, it does not require using reflection until the actual exception occurs if constructed properly.  The following line if used once an exception is thrown would pass along method information that can be extracted:

    Reflection.MethodBase.GetCurrentMethod()


    Anyways, like I said it is easy to criticize code that was written by others when they can not defend it, but it certainly does seem that the architecture used in your example can be refined and refactored into a more streamlined version that will accomplish the same goals.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Friday, February 5, 2010 9:03 AM

All replies

  • User559104930 posted

    What is the goal you are trying to accomplish in your code? This kind of abstraction is typically considered an "anti-pattern", adding needless complexity to the code base. What happens when the object's constructor requires a parameter? You may look into using an IoC framework such as Unity to solve your problem.

    Tuesday, February 2, 2010 9:38 AM
  • User-952121411 posted

    I agree with the previous poster's comments; if you could elaborate as to why you are using this method to create the objects, that would help.  It almost appears that it was an attempt at a Factory pattern to churn out objects based on the criteria, but in your case all I can see happening, is the type of object requested explicitly is then returned.  However to get from Point A to Point B, you have a lot of overhead including the use of Reflection for each object created.  I too may be able to give some more meaningful advice if the intended purpose of this design is expanded on some.

    Thank you, 

    Tuesday, February 2, 2010 10:58 AM
  • User1238834067 posted

    Thanks a lot  for the updates.

    It was the existing design in our project and the architect was no longer with the project :(.I also felt that it was unnecessary overhead using reflection.

     I guess only thing it served was to ensure that only one instance of business class object wasused as its using static hash table to hold the instance .

    Is this the better approach.?

    it it scalable?

    There might be better approaches if we really want to maintain the single instance using singleton or abstract the instance using factory pattern?

     I spoke to some of the fellow developers but they told me that its used to know the methods and types used in class and log it whenever any exception occured.

    Appreciate your thoughts

    I am placing the entire code here.

     

    namespace xxx

    {
        using System;
        using System.Linq;
        using System.Text;
        using System.Reflection;
        using System.Collections;
        using System.CodeDom.Compiler;
        using System.Collections.Generic;
        using Microsoft.CSharp;
        using System.IO;

        public class TypeInterceptor
        {
            private static Hashtable _htTypes = null;
            private static Hashtable _htTypesSynchronized = null;

            private static string _strMethodTemplate = "[MODIFIER] override [RETURN_TYPE] [METHOD]" + Environment.NewLine +
            "{" + Environment.NewLine +
                "Lib.PreProcess([PARAMETERS]);" + Environment.NewLine +
                "[RETURN_VARIABLE_DECLARATION]" + Environment.NewLine +
                "try" + Environment.NewLine +
                "{" + Environment.NewLine +
                "[RETURN_VARIABLE] base.[METHOD_CALL];" + Environment.NewLine +
                "}" + Environment.NewLine +
                "catch(Exception exc)" + Environment.NewLine +
                "{" + Environment.NewLine +
                "Lib.ProcessException(exc, [PARAMETERS_DATA]);" + Environment.NewLine +
                "}" + Environment.NewLine +

                "finally" + Environment.NewLine +
                "{" + Environment.NewLine +
                "Lib.PostProcess([PARAMETERS]);" + Environment.NewLine +
                "}" + Environment.NewLine +

                "[RETURN]" + Environment.NewLine +
            "}" + Environment.NewLine + Environment.NewLine;

            static TypeInterceptor()
            {
                _htTypes = new Hashtable();
                _htTypes.Clear();
                _htTypesSynchronized = Hashtable.Synchronized(_htTypes);
            }

            public static T CreateObject<T>() where T : new()
            {
                T targetObject = default(T);
                Type typeGenerated = null;

                string strCallingAssembly = Assembly.GetAssembly(typeof(T)).CodeBase.ToString().Replace("file:///", string.Empty);

                if (!_htTypes.Contains(typeof(T).ToString()))
                {
                    string str = BuildClass<T>();
                    typeGenerated = GenerateType<T>(str, strCallingAssembly);
                    _htTypes.Add(typeof(T).ToString(), typeGenerated);
                }
                else
                {
                    typeGenerated = (Type)_htTypes[typeof(T).ToString()];
                }

                targetObject = (T)Activator.CreateInstance(typeGenerated);
                return targetObject;
            }

            private static string BuildClass<T>()
            {
                StringBuilder sbClass = null;

                try
                {
                    sbClass = new StringBuilder();
                    sbClass.Append("using System;");
                    sbClass.Append("using Microsoft.IT.RelationshipManagement.Internal.CISF.Infrastructure;");
                    sbClass.Append("namespace " + typeof(T).Namespace.ToString() + Environment.NewLine + "{" + Environment.NewLine);
                    sbClass.Append("class " + typeof(T).Name + "_wrapper : " + typeof(T).ToString() + Environment.NewLine + "{" + Environment.NewLine);

                    sbClass.Append("public " + typeof(T).Name + "_wrapper() {}");

                    MethodInfo[] methods = typeof(T).GetMethods(BindingFlags.DeclaredOnly | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);

                    foreach (MethodInfo mi in methods)
                    {
                        if (!(mi.IsVirtual && (mi.IsFamily || mi.IsPublic) && (mi.DeclaringType.ToString() == typeof(T).ToString())))
                        {
                            continue;
                        }

                        ParameterInfo[] paramInfo = mi.GetParameters();

                        string strParameters = string.Empty;
                        string strParameters_Call = string.Empty;
                        string strParameters_ObjectArray = string.Empty;
                        string strFuncName = typeof(T).Namespace.ToString() + "." + mi.Name;

                        foreach (ParameterInfo pi in paramInfo)
                        {
                            strParameters = strParameters + pi.ParameterType.ToString() + " " + pi.Name + ", ";
                            strParameters_Call = strParameters_Call + pi.Name + ", ";
                            strParameters_ObjectArray = strParameters_ObjectArray + pi.Name + ", ";
                        }

                        int idx = strParameters.LastIndexOf(", ");
                        int idx_call = strParameters_Call.LastIndexOf(", ");
                        int idx_objAry = strParameters_ObjectArray.LastIndexOf(", ");

                        if (idx > 0)
                        {
                            strParameters = strParameters.Substring(0, idx);
                            strParameters_Call = strParameters_Call.Substring(0, idx_call);
                            strParameters_ObjectArray = strParameters_ObjectArray.Substring(0, idx_objAry);
                        }
                        string strReturnType = GetReturnType(mi);

                        string strMethodDefinition = _strMethodTemplate.Replace("[METHOD]", mi.Name + "(" + strParameters + ")");
                        strMethodDefinition = strMethodDefinition.Replace("[METHOD_CALL]", mi.Name + "(" + strParameters_Call + ")");
                        strMethodDefinition = strMethodDefinition.Replace("[RETURN_TYPE]", strReturnType);
                        strMethodDefinition = strMethodDefinition.Replace("[PARAMETERS]", "\"" + strFuncName + "\"" + ", new object[] {" + strParameters_ObjectArray + "}");
                        strMethodDefinition = strMethodDefinition.Replace("[PARAMETERS_DATA]", "new object[] {" + strParameters_ObjectArray + "}");
                        strMethodDefinition = strMethodDefinition.Replace("[MODIFIER]", GetModifier(mi));

                        string strReturn = mi.ReturnType.ToString();
                        //string strBaseType = mi.ReturnType.BaseType.FullName;

                        if ("System.Void" == strReturn)
                        {
                            strMethodDefinition = strMethodDefinition.Replace("[RETURN_VARIABLE_DECLARATION]", string.Empty);
                            strMethodDefinition = strMethodDefinition.Replace("[RETURN_VARIABLE]", string.Empty);
                            strMethodDefinition = strMethodDefinition.Replace("[RETURN]", "return;");
                        }
                        else
                        {
                            //if ("System.ValueType" == strBaseType)
                            //{
                            //    strMethodDefinition = strMethodDefinition.Replace("[RETURN_VARIABLE_DECLARATION]", strReturnType + " ret = new " + GetReturnType(mi) + "();");
                            //}
                            //else
                            //{
                            //    strMethodDefinition = strMethodDefinition.Replace("[RETURN_VARIABLE_DECLARATION]", strReturnType + " ret = default(" + strReturnType + ");");
                            //}
                            strMethodDefinition = strMethodDefinition.Replace("[RETURN_VARIABLE_DECLARATION]", strReturnType + " ret = default(" + strReturnType + ");");

                            strMethodDefinition = strMethodDefinition.Replace("[RETURN_VARIABLE]", " ret = ");
                            strMethodDefinition = strMethodDefinition.Replace("[RETURN]", "return ret;");
                        }

                        sbClass.Append(strMethodDefinition);
                        sbClass.Append(Environment.NewLine);
                    }

                    sbClass.Append("}}");
                }
                catch (Exception ex)
                {
                    string str = ex.Message;
                    throw;
                }

                return sbClass.ToString();
            }

            private static string GetReturnType(MethodInfo mi)
            {
                string strReturnType = string.Empty;
                if ("System.Void" == mi.ReturnType.ToString())
                {
                    strReturnType = "void";
                }
                else
                {
                    strReturnType = mi.ReturnType.ToString();
                    strReturnType = strReturnType.Replace("`1", "");
                    strReturnType = strReturnType.Replace("[", "<");
                    strReturnType = strReturnType.Replace("]", ">");

                }

                return strReturnType;
            }

            private static string GetModifier(MethodInfo mi)
            {
                string strModifier = string.Empty;

                if (mi.IsPublic)
                {
                    strModifier = "public";
                }
                else if (mi.IsFamily)
                {
                    strModifier = "protected";
                }

                return strModifier;
            }

            private static Type GenerateType<T>(string strClass, string strCallingAssembly)
            {
                Type typ = null;
                try
                {
                    CSharpCodeProvider myCodeProvider = new CSharpCodeProvider();

                    string[] referenceAssemblies = { "System.dll", "System.Data.dll", "System.Xml.dll", Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().CodeBase), "CISF.DataEntities.dll").Replace("file:\\", string.Empty), Assembly.GetExecutingAssembly().CodeBase.ToString().Replace("file:///", string.Empty), strCallingAssembly };
                    CompilerParameters myCompilerParameters = new CompilerParameters(referenceAssemblies, string.Empty);

                    myCompilerParameters.GenerateExecutable = false;

                    CompilerResults cr = myCodeProvider.CompileAssemblyFromSource(myCompilerParameters, strClass);

                    string s = string.Empty;
                    foreach (string str in cr.Output)
                    {
                        s = str + Environment.NewLine;
                    }

                    typ = cr.CompiledAssembly.GetType(typeof(T).Namespace + "." + typeof(T).Name + "_wrapper");
                }
                catch (Exception ex)
                {
                    string str = ex.Message;
                }

                return typ;
            }
        }
    }

    Friday, February 5, 2010 1:23 AM
  • User-952121411 posted

    There might be better approaches if we really want to maintain the single instance using singleton or abstract the instance using factory pattern?
     

    Agreed.  If your overall goal is to make sure that only one instance of the class is being used, then the Singleton Design can be implemented in a much more streamlined manner in its simplest form.  In a nutshell, all that needs to be done is check if an instance exists or not and either return the existing instance or a new one.  The additional code in your example seems unnecessary, however it is always difficult to see the entire picture just from a little code and a few descriptions. Below is some additional information:

    Exploring the Singleton Design Pattern:

    http://msdn.microsoft.com/en-us/library/ee817670.aspx

    As far as exception handling goes, I agree it is nice to know what the offending method was.  But this is easy, it does not require using reflection until the actual exception occurs if constructed properly.  The following line if used once an exception is thrown would pass along method information that can be extracted:

    Reflection.MethodBase.GetCurrentMethod()


    Anyways, like I said it is easy to criticize code that was written by others when they can not defend it, but it certainly does seem that the architecture used in your example can be refined and refactored into a more streamlined version that will accomplish the same goals.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Friday, February 5, 2010 9:03 AM
  • User1238834067 posted

    [Resending as Weekend got in between :)] 

    Monday, February 8, 2010 1:27 AM