在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

{

ITestClass Members#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<string, object> gtc = ObjectFactory.CreateObject<IGenericTestClass<string, object>>();
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。
//文章结束