这段时间,除了公司的项目之外;回家之后,自己还要写一个简单的CMS系统
当然,本来很简单的一个项目,但是我为了其足够的强大,所以在其中加入了某些复杂概念;且面向概念编程要将这些复杂概念用编码实现;
在项目过程中,就遇到了一个简单的问题:
项目中通用数据源 SuperSource是核心的数据源类;
其中有一个函数 object GetEntity(stringkey);
但是,我希望写出一种泛型 SuperSource<T> ,我希望有一个函数 T GetEntity(stringkey)
那么,SuperSource 和 SuperSource<T> 如何定义,如何决定谁做父亲,谁做儿子?
如果 如下编码
public class SuperSource<T>{
public virtual T GetEntity(string key){
return null;
}
}
public class SuperSource: SuperSource<object>{
public overrideobject GetEntity(stringkey){
returnnull;
}
}
函数就保持了一致性(父类的调用会自动定位到子类),且符合我们上面的要求;
但是,假如我还有
SuperSource<Product> 和 SuperSource<Article> 和 SuperSource<Link>
正好,我有一个通用的编辑界面:SuperEdit.aspx
该页面的功能: 绑定任何 一个“超级数据源”,且GetEntity(urlKey) ,且将返回值绑定到界面;
如果 用上面的继承方式,我们会发现:
Product model = SuperSource<Product>.GetEntity(urlKey)
Article model = SuperSource<Article>.GetEntity(urlKey)
Linkmodel = SuperSource<Link>.GetEntity(urlKey)
object model = SuperSource.GetEntity(urlKey)
前面的引用,我们可以用 object 来接收,但是后面 尖括号中赤裸裸的类名,将让SuperEdit.aspx 不具备无敌的扩展性;
如何让 SuperEdit.aspx 的代码中不出现任何 Product,Article,Link这些关系到具体实例的 酱油类(因为逻辑而需要,但不因概念而需要的类)呢??
——就是说:SuperSource<T> 这些类如何找到一个公共父类呢?
当天晚上没能想出解决办法,于是就睡觉去了;
第二天,突然再次想到 SuperSource 和 SuperSource<T>的继承关系:
如果:
public class SuperSource{
public virtual objectGetEntity(string key){
returnnull;
}
}
public class SuperSource<T>: SuperSource{
public override T GetEntity(string key){
returnnull;
}
}
结果很不幸,编译错误:因为可以意会不可言传的某些机制;(我将SuperSource<T> 加上sealed 想避免这个机制,但是编译器依然报错)
那么,究竟该怎么做呢??
于是我想到了我们经常使用的一个类:
SqlConnection DbConnectionIDbConnetion数据库连接类
我们用 SqlConnection.CreateCommand() =>SqlCommand
DbConnetion.CreateCommand() =>DbCommand
IDbConnection.CreateCommand() =>IDbCommand
凭什么微软就可以在继承父类的同时,改变父类的函数的类型
——难道就因为C#是他发明的,所以他就有权利避开编译器??
经过反编译之后,结果确实不是那样:
微软运用了间接继承(我不知道该怎么定义这个机制,就用“间接继承”吧)机制!
于是我写出了 自己想要的 SuperSource 代码,代码如下:
public class SuperSource{
protected virtual object InnerGetEntity(string key){ returnnull; }
publc object GetEntity(stringkey){ return InnerGetEntity(key); }
}
public class SuperSource<T>: SuperSource{
protected overridt object InnerGetEntity(string key){ return GetEntity(key);}
publc new virtual T GetEntity(stringkey){ return null; }
}
public class ProdcutSuperSource: SuperSource<Product>{ //酱油类
publc overridt Product GetEntity(string key){ return new Product(); }
}
GetEntity(string key) 之间已经没有了任何继承关系;
父子之间实现继承的是 一个不对外公布的 InnerGetEntity(string key) 函数;
而且,你会惊讶的发现:
GetEntity(string key) 虽然不具备继承关系,
但是父类的引用依然会自动定位到子类 的 GetEntity(string key)
——这就是我所说的 间接继承 !
现在回到项目 SuperEdit.aspx:
SuperSource 现在是所有 “超级数据源”的父类;
SuperSource 可以等于 SuperSource<Product> 或者 SuperSource<Article> 或者SuperSource<Link>
SuperEdit.aspx中就只需要下面一行代码, SuperSource 就不用指定具体的 酱油类 了!
object model = SuperSource.GetEntity(urlKey)
顺便,我们扩展一下上面的代码:
public class TestSource: SuperSource<object>{
public overridt object GetEntity(string key){ returnnull; }
}
我们会发现 TestSource 和 SuperSource 是等价的!
相当于是说 :
子类继承了父类,父类的变种继承了子类——真够的……
创建除了这样一种功能强大,但是如此的SuperSource 类,我深感罪孽深重!
哎,不写了……
舒小龙
2012-01-1010:39