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