您好,欢迎访问一九零五行业门户网

背后的故事之 - 快乐的Lambda表达式(二)

上一篇 背后的故事之 – 快乐的lambda表达式(一)我们由浅入深的分析了一下lambda表达式。知道了它和委托以及普通方法的区别,并且通过测试对比他们之间的性能,然后我们通过il代码深入了解了lambda表达式,以及介绍了如何在.net中用lambda表达式来实现javascript中流行的一些模式。
今天,我们接着来看lambda表达式在.net中还有哪些新鲜的玩法。
lambda表达式玩转多态
lambda如何实现多态?我们用抽象类和虚方法了,为什么还要用lambda这个玩意?且看下面的代码:
class mybaseclass { public action someaction { get; protected set; } public mybaseclass() { someaction = () => { //do something! }; } } class myinheritedclass : mybaseclass { public myinheritedclass() { someaction = () => { //do something different! }; } }
我们的基类不是抽象类,也没有虚方法,但是把属性通过委托的方式暴露出来,然后在子类中重新为我们的someaction赋予一个新的表达式。这就是我们实现多态的过程,当然父类中的someaction的set有protected的保护级别,不然就会被外部随易修改了。但是这还不完美,父类的someaction在子类中被覆盖之后,我们彻底访问不到它了,要知道真实情况是我们可以通过base来访问父类原来的方法的。接下来就是实现这个了
class mybaseclass { public action someaction { get; private set; } stack<action> previousactions; protected void addsomeaction(action newmethod) { previousactions.push(someaction); someaction = newmethod; } protected void removesomeaction() { if(previousactions.count == 0) return; someaction = previousactions.pop(); } public mybaseclass() { previousactions = new stack<action>(); someaction = () => { //do something! }; } }
上面的代码中,我们通过addsomeaction来实现覆盖的同时,将原来的方法保存在previousactions中。这样我们就可以保持两者同时存在了。
大家知道子类是不能覆盖父类的静态方法的,但是假设我们想实现静态方法的覆盖呢?
void main() { var mother = hotdaughter.activator().message; //mother = "i am the mother" var create = new hotdaughter(); var daughter = hotdaughter.activator().message; //daughter = "i am the daughter" } class coolmother { public static func<coolmother> activator { get; protected set; } //we are only doing this to avoid null references! static coolmother() { activator = () => new coolmother(); } public coolmother() { //message of every mother message = "i am the mother"; } public string message { get; protected set; } } class hotdaughter : coolmother { public hotdaughter() { //once this constructor has been "touched" we set the activator ... activator = () => new hotdaughter(); //message of every daughter message = "i am the daughter"; } }
这里还是利用了将lambda表达式作为属性,可以随时重新赋值的特点。当然这只是一个简单的示例,真实项目中并不建议大家这么去做。
方法字典
实际上这个模式我们在上一篇的返回方法中已经讲到了,只是没有这样一个名字而已,就算是一个总结吧。故事是这样的,你是不是经常会写到switch-case语句的时候觉得不够优雅?但是你又不想去整个什么工厂模式或者策略模式,那怎么样让你的代码看起来高级一点呢?
public action getfinalizer(string input) { switch { case "random": return () => { /* ... */ }; case "dynamic": return () => { /* ... */ }; default: return () => { /* ... */ }; } } //-------------------变身之后----------------------- dictionary<string, action> finalizers; public void buildfinalizers() { finalizers = new dictionary<string, action>(); finalizers.add("random", () => { /* ... */ }); finalizers.add("dynamic", () => { /* ... */ }); } public action getfinalizer(string input) { if(finalizers.containskey(input)) return finalizers[input]; return () => { /* ... */ }; }
好像看起来是不一样了,有那么一点味道。但是一想是所有的方法都要放到那个buildfinalizers里面,这种组织方法实在是难以接受,我们来学学插件开发的方式,让它自己去找所有我们需要的方法。
static dictionary<string, action> finalizers; // 在静态的构造函数用调用这个方法 public static void buildfinalizers() { finalizers = new dictionary<string, action>(); // 获得当前运行程序集下所有的类型 var types = assembly.getexecutingassembly().gettypes(); foreach(var type in types) { // 检查类型,我们可以提前定义接口或抽象类 if(type.issubclassof(typeof(mymotherclass))) { // 获得默认无参构造函数 var m = type.getconstructor(type.emptytypes); // 调用这个默认的无参构造函数 if(m != null) { var instance = m.invoke(null) as mymotherclass; var name = type.name.remove("mother"); var method = instance.mymethod; finalizers.add(name, method); } } } } public action getfinalizer(string input) { if(finalizers.containskey(input)) return finalizers[input]; return () => { /* ... */ }; }
如果要实现插件化的话,我们不光要能够加载本程序集下的方法,还要能随时甚至运行时去加载外部的方法,请继续往下看:
internal static void buildinitialfinalizers() { finalizers = new dictionary<string, action>(); loadplugin(assembly.getexecutingassembly()); } public static void loadplugin(assembly assembly) { var types = assembly.gettypes(); foreach(var type in types) { if(type.issubclassof(typeof(mymotherclass))) { var m = type.getconstructor(type.emptytypes); if(m != null) { var instance = m.invoke(null) as mymotherclass; var name = type.name.remove("mother"); var method = instance.mymethod; finalizers.add(name, method); } } } }
现在,我们就可以用这个方法,给它指定程序集去加载我们需要的东西了。
最后留给大家一个问题,我们能写递归表达式么?下面的方法如果用表达式如何写呢?
int factorial(int n) { if(n == 0) return 1; else return n * factorial(n - 1); }
以上就是背后的故事之 - 快乐的lambda表达式(二)的内容。
其它类似信息

推荐信息