LiteMDA中支持Generic的BusinessObjectFactory实现

在C# 2.0中提供了Generic支持,我们的Factory就也应该支持Generic,以下是我在LiteMDA的BusinessObjectFactory中的实现,同时支持Generic和非Generic的类。

关于Interface及其对应的Assembly和Class的描述信息存在以下的BusinessObjectConfiguration.config中:
<?xml version="1.0" encoding="utf-8"?>
<BusinessObjectConfiguration>
  
<xmlSerializerSection type="LiteMDA.Configuration.BusinessObjectConfiguration, LiteMDA.Configuration, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
    
<BusinessObjectConfiguration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
      
<VisibleBusinessObjects>
        
<BusinessObject>
          
<InterfaceName>LiteMDA.BusinessObjectFactory.Test.ITestClass</InterfaceName>
          
<Class AssemblyName="LiteMDA.BusinessObjectFactory.Test.exe" ClassName="LiteMDA.BusinessObjectFactory.Test.TestClass" />
        
</BusinessObject>
        
<BusinessObject>
          
<InterfaceName>LiteMDA.BusinessObjectFactory.Test.IGenericTestClass`2[System.String,System.Object]</InterfaceName>
          
<Class AssemblyName="LiteMDA.BusinessObjectFactory.Test.exe" ClassName="LiteMDA.BusinessObjectFactory.Test.GenericTestClass`2[System.String,System.Object]" />
        
</BusinessObject>
        
<BusinessObject>
          
<InterfaceName>LiteMDA.BusinessObjectFactory.Test.ITestClass2</InterfaceName>
          
<Class AssemblyName="LiteMDA.BusinessObjectFactory.Test.exe" ClassName="LiteMDA.BusinessObjectFactory.Test.GenericTestClass`2[System.String,System.Object]" />
        
</BusinessObject>
      
</VisibleBusinessObjects>
    
</BusinessObjectConfiguration>
  
</xmlSerializerSection>
</BusinessObjectConfiguration>

以上的Configuration中定义了三个可以被BusinessObjectFactory构造的类,构造时只需提供Interface,这里给出了三种典型的情况,一个是非Generic、一个是接口为Generic,类也为Generic,第三个是接口非Generic,类Generic。

BusinessObjectFactory的源码如下:
using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using LiteMDA.Configuration;
using Microsoft.Practices.EnterpriseLibrary.Configuration;

namespace LiteMDA.BusinessObjectFactory
{
    
/// <summary>
    
/// ObjectFactory is the only gateway for creating Business Objects.
    
/// </summary>

    public sealed class ObjectFactory
    
{
        
private ObjectFactory()
        
{
        }


        
/// <summary>
        
/// _ObjectMap saves all the BOI/BO mapping pairs, this field will 
        
/// be constructed from the BOI exposing configuration file at the 
        
/// first time when the CreateObject method is invoked.
        
/// </summary>

        private static BusinessObjectConfiguration _BOC = null;

        
/// <summary>
        
/// Create a Business Object.
        
/// </summary>
        
/// <typeparam name="TInterface">An exposed Business Object Interface.</typeparam>
        
/// <returns>Return Business Object instance that implementing TInterface.</returns>
        
/// <exception cref="LiteMDA.BusinessObjectFactory.InterfaceNotExposedException">
        
///    Thrown when the specified TInterface is not in the exposed interface list.
        
/// </exception>
        
/// <exception cref="LiteMDA.BusinessObjectFactory.ConfigurationFileFormatErrorException">
        
///    Thrown when the the format of the configuration file for BO/BOI mapping is error.
        
/// </exception>

        public static TInterface CreateObject<TInterface>()
        
{
            
if (_BOC == null)
            
{
                
// if this is the first time invoking CreateObject, load BOI/BO 
                
// mapping pairs from the configuration file first.
                _BOC = ConfigurationManager.GetConfiguration("BusinessObjectConfiguration"as BusinessObjectConfiguration;
            }


            AssemblyClass ac 
= _BOC[typeof(TInterface).ToString()];

            
if (ac != null)
            
{
                
//create object instance from the specified assemblyName and className
                Assembly ass = Assembly.LoadFile(AppDomain.CurrentDomain.BaseDirectory + ac.AssemblyName);
                
if (ac.ClassName.Contains("`"))
                
{
                    
//It is a generic type, so fetch Type Parameters and bind then to the type before CreateInstance
                    Type t = ass.GetType(ac.ClassName.Substring(0, ac.ClassName.IndexOf("[")));
                    
string typeParamListStr = ac.ClassName.Substring(ac.ClassName.IndexOf("["+ 1).TrimEnd(']');
                    
string[] typeParamNames = typeParamListStr.Split(',');
                    Type[] typeParams 
= new Type[typeParamNames.Length];
                    
for (int i = 0; i < typeParamNames.Length; i++)
                    
{
                        typeParams[i] 
= Type.GetType(typeParamNames[i].Trim());
                    }

                    t 
= t.MakeGenericType(typeParams);
                    
return (TInterface)Activator.CreateInstance(t);
                }

                
else
                
{
                    
return (TInterface)ass.CreateInstance(ac.ClassName);
                }

            }

            
else
            
{
                
throw new InterfaceNotExposedException(typeof(TInterface).ToString());
            }

        }

    }

}


几个测试类和接口代码如下:

ITestClass.cs
using System;
using System.Collections.Generic;
using System.Text;

namespace LiteMDA.BusinessObjectFactory.Test
{
    
public interface ITestClass
    
{
        
void TestMethod();
    }

}


ITestClass2.cs
using System;
using System.Collections.Generic;
using System.Text;

namespace LiteMDA.BusinessObjectFactory.Test
{
    
public interface ITestClass2
    
{
        
void TestMethod2();
    }

}


IGenericTestClass.cs
using System;
using System.Collections.Generic;
using System.Text;

namespace LiteMDA.BusinessObjectFactory.Test
{
    
public interface IGenericTestClass<T, U>
    
{
        
void TestMethod();
    }

}


TestClass.cs
using System;
using System.Collections.Generic;
using System.Text;

namespace LiteMDA.BusinessObjectFactory.Test
{
    
public class TestClass : ITestClass
    
{
        
#region ITestClass Members

        
public void TestMethod()
        
{
            System.Windows.Forms.MessageBox.Show(
"OK");
        }


        
#endregion

    }

}


GenericTestClass.cs
using System;
using System.Collections.Generic;
using System.Text;

namespace LiteMDA.BusinessObjectFactory.Test
{
    
public class GenericTestClass<T, U> : IGenericTestClass<T, U>, ITestClass2
    
{
        
public void TestMethod()
        
{
            System.Windows.Forms.MessageBox.Show(
"OK2");
        }


        
public void TestMethod2()
        
{
            System.Windows.Forms.MessageBox.Show(
"OK3");
        }

    }

}


测试代码如下:
        private void btnTestCreateBusinessObject_Click(object sender, EventArgs e)
        
{
            ITestClass tc 
= ObjectFactory.CreateObject<ITestClass>();
            tc.TestMethod();
            IGenericTestClass
<stringobject> gtc = ObjectFactory.CreateObject<IGenericTestClass<stringobject>>();
            gtc.TestMethod();
            ITestClass2 tc2 
= ObjectFactory.CreateObject<ITestClass2>();
            tc2.TestMethod2();

        }

--
顺便说一下,以上的Configuration使用EnterpriseLibrary读写的。在vs.net 2005 beta2中使用EntLib我费了一番波折才搞定,这里说以下怎样设置,免得大家再走弯路。

你需要先用操作系统的搜索功能搜索entlib中src目录下所有包含"define VS2003"的.cs文件,大概十几个,把所有这些文件顶部的"VS2003"改成"VS2005B2",然后用vs.net 2005 beta2(vc#2005beta2也一样)打开EnterpriseLibrary.sln重新编译所有程序集,同时请使用重新编后的Enterprise Library Configuration Tool来建立Application的App.config或web.config。

//文章结束
posted @ 2005-08-10 12:10  Teddy's Knowledge Base  Views(1662)  Comments(19Edit  收藏  举报