背景
我们考虑一下这样的一个场景我们需要开发了一个用于排序的通用的可扩展的库利用该库用户可以自定义排序规则(比较大小)以及需要进行排序的数据类型而同时我们开发了一个应用程序在该应用程序中我们可以让用户选择排序算法来进行排序由于我们的排序库是可扩展的因此在开发应用程序的时候我们并不知道会有多少种排序算法可供使用因此我需要通过读取配置文件来动态的加载排序算法
排序库SortLib
在SortLib中我们定义所有排序算法的通用接口ISortAlgorithm
public interface ISortAlgorithm<T>
{
void Sort(List<T> source Func<T T int> compare);
}
比如我们有一个排序算法叫HeapSort注意该算法可能在SortLib程序集中也可能不在
public class HeapSortAlgorithm<T> : ISortAlgorithm<T>
{
public void Sort(List<T> source Func<T T int> compare)
{
//TODO: sort the source
}
}
应用程序SortApp
动态创建排序算法
我们知道要动态的创建HeapSortAlgorithm只需要获取到其类型然后利用ActivatorCreateInstance就行例如:
ActivatorCreateInstance(AssemblyLoad(assembly)GetType(full type name);
而在此处由于我们的HeapSortAlgorithm是个泛型类则需要给泛型中的T赋予实际的类型我们可以通过先获取泛型类型再通过MakeGenericType来创建实际的类型如下
string assemblyName = stringEmpty;
string fullTypeName = stringEmpty;
//TODO: 读取配置文件赋值给assemblyName和fullTypeName
Type[] typeArgs = { typeof(int) };
Type algTypeGen = AssemblyLoad(assemblyName)GetType(fullTypeName);
//TODO: 判断algTypeGen是否实现了ISortAlgorithm<T>接口
// 获取HeapSortAlgorithm<int>类型
Type algType = algTypeGenMakeGenericType(typeArgs);
HeapSortAlgorithm<int> heapSortAlg = ActivatorCreateInstance(algType);
如此这般我们的HeapSort算法就可以用上
配置文件
为了使我们的应用程序能够用上HeapSort我们将其添加到我们的配置文件中去如下
<SortAlgorithms>
<Algorithm name=HeapSort assembly=SortLib type=SortLibHeapSortAlgorithm` />
</SortAlgorithms>
注意到配置中type一项设置为SortLibHeapSortAlgorithm`这是因为泛型类HeapSortAlgorithm<T>在运行过程中它的实际名称是HeapSortAlgorithm`这也可以通过typeof(HeapSortAlgorithm<>)得到(注关于这点不知道这个泛型的名称会不会变成HeapSortAlgorithm`之类的笔者还不太确定希望有哪个大大们赐教)
另如何去读取配置文件的代码在本文中我就不贴出来了可以自己写ConfigurationSection类后来获取(推荐)或者直接通过c#中读取XML文件的方式来实现:)
判断类型是否实现泛型接口
判断algTypeGen是否实现了ISortAlgorithm<T>接口可以通过对algTypeGen实现的所有接口与ISortAlgorithm<>循环比对即可实现
Type baseSortAlgType = typeof(ISortAlgorithm<>);
bool isImplemented = algTypeGenGetInterfaces()Any(x =>
xIsGenericType &&
xGetGenericTypeDefinition() == baseSortAlgType);
后记
在本文中我们了解了如何通过配置实现动态创建泛型类型的实例希望对大家有所帮助