走进Linq-Linq to SQL源代码赏析 Table的获取过程
[2] 走进Linq-Linq to SQL源代码赏析 Table
[3] 走进Linq-Linq to SQL源代码赏析 Table
系列文章导航:
不能不说的C#特性-迭代器(下),yield以及流的延迟计算
走进Linq-Linq to SQL How do I(1)
走进Linq-Linq to SQL How do I(2)
走进Linq-Linq to SQL How do I(3)
走进Linq-Linq to SQL源代码赏析 Table
走进Linq-Linq to SQL源代码赏析之Provider的初始化
走进Linq-Linq to SQL源代码赏析,通过Linq to SQL看Linq
代码中的注释说的很详细了,先看看DataContext类里是否有Table<TEntity>的属性,而只有在强类型的DataContext情况下才会有的。所以只有在强类型的情况下才会在初始化DataContext的时候设置这些Table<TEntity>属性的值,从本篇后面的介绍可以看到,获取Table<TEntity>还不是个简单的事情,性能损耗比较大,所以框架默认提供的DataContext比强类型的DataContext更轻型,在上一章中有人问到DataContext是不是轻型的,我觉得如果使用框架提供的是很轻型的,实例化一个没有什么大的性能消耗。下面来看我们经常调用的GetTable方法:
{
this.CheckDispose();
//调用MetaModel的GetTable方法获得MetaTable对象
//MetaModel代表的是数据库和DataContext之间的映射
//而MetaModel代表的是表和对象之间的映射
MetaTable metaTable = this.services.Model.GetTable(typeof(TEntity));
if (metaTable == null)
{
throw Error.TypeIsNotMarkedAsTable(typeof(TEntity));
}
//调用本类的GetTable方法
ITable table = this.GetTable(metaTable);
//关于这里的ITable接口和ElementType属性有更多的讨论
if (table.ElementType != typeof(TEntity))
{
throw Error.CouldNotGetTableForSubtype(typeof(TEntity),
metaTable.RowType.Type);
}
return (Table<TEntity>)table;
}
private ITable GetTable(MetaTable metaTable)
{
ITable table;
//先查看字典中是否有这个table,该字典是以MetaTable为key,以ITable为value的
if (!this.tables.TryGetValue(metaTable, out table))
{
//通过检查表之间的关联难验证表的合法性
ValidateTable(metaTable);
//反射ITable对象
table = (ITable)Activator.CreateInstance(typeof(Table<>).
MakeGenericType(new Type[] { metaTable.RowType.Type }),
BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance,
null, new object[] { this, metaTable }, null);
//通过反射获取ITable对象后,还将其存储在字典中,可以看到这个字典起一个缓存的作用
//以后就可以直接从字典里取了,也就是这个GetTable的过程并不是每次都有反射的性能损耗
this.tables.Add(metaTable, table);
}
return table;
}
MetaTable metaTable = this.services.Model.GetTable(typeof(TEntity));
这一句是调用MetaModel的GetTable方法,MetaModel根据映射的不同有两种实现:AttributeMetaModel和MappedMetaModel。
得到MetaTable对象后,就可以调用Table<TEntity>的构造函数来获取Table<TEntity>对象了,但是这里却使用的是反射:
table = (ITable)Activator.CreateInstance(typeof(Table<>).MakeGenericType(new Type[] { metaTable.RowType.Type }), BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance, null, new object[] { this, metaTable }, null);
为什么不直接new呢?原来微软将Table<TEntity>的构造函数设置为私有的了,无法直接使用new调用,
在这里除了构造函数是私有的外,最主要的原因是Table<>是一个泛型类,而这个时候还不知道具体的泛型参数,所以我们只能用泛型了,也就是说即使这里构造函数是私有的,我们也只能用反射构建Table<>的实例。谢谢IVony的提醒。但是这也并不妨碍后面使用的变形的单件模式。
也许是为了防止客户代码任意的创建Table<TEntity>对象,而将构造函数设为私有的吧,也许有人会马上想到,这里应该使用单件模式啊,防止客户端任意创建实例。