转载:http://www.cnblogs.com/jesse2013/p/happylambda-part2.html
快乐的Lambda表达式
上一篇 背后的故事之 - 快乐的Lambda表达式(一)我们由浅入深的分析了一下Lambda表达式。知道了它和委托以及普通方法的区别,并且通过测试对比他们之间的性能,然后我们通过IL代码深入了解了Lambda表达式,以及介绍了如何在.NET中用Lambda表达式来实现JavaScript中流行的一些模式。
今天,我们接着来看Lambda表达式在.NET中还有哪些新鲜的玩法。
Lambda表达式玩转多态
Lambda如何实现多态?我们用抽象类和虚方法了,为什么还要用Lambda这个玩意?且看下面的代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
class MyBaseClass
{
public Action get ; protected set ;
public MyBaseClass()
{
SomeAction
{
//Do
};
}
}
class MyInheritedClass
{
public MyInheritedClass()
{
SomeAction
//Do
};
}
}
|
我们的基类不是抽象类,也没有虚方法,但是把属性通过委托的方式暴露出来,然后在子类中重新为我们的SomeAction赋予一个新的表达式。这就是我们实现多态的过程,当然父类中的SomeAction的set有protected的保护级别,不然就会被外部随易修改了。但是这还不完美,父类的SomeAction在子类中被覆盖之后,我们彻底访问不到它了,要知道真实情况是我们可以通过base来访问父类原来的方法的。接下来就是实现这个了:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
class MyBaseClass
{
public Action get ; private set ;
Stack<Action>
protected void AddSomeAction(Action
{
previousActions.Push(SomeAction);
SomeAction
}
protected void RemoveSomeAction()
{
if (previousActions.Count
return ;
SomeAction
}
public MyBaseClass()
{
previousActions new Stack<Action>();
SomeAction
//Do
};
}
}
|
上面的代码中,我们通过AddSomeAction来实现覆盖的同时,将原来的方法保存在previousActions中。这样我们就可以保持两者同时存在了。
大家知道子类是不能覆盖父类的静态方法的,但是假设我们想实现静态方法的覆盖呢?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
void Main()
{
var mother
//mother
var create new HotDaughter();
var daughter
//daughter
}
class CoolMother
{
public static Func<CoolMother> get ; protected set ;
//We
static CoolMother()
{
Activator new CoolMother();
}
public CoolMother()
{
//Message
Message "I ;
}
public string Message get ; protected set ;
}
class HotDaughter
{
public HotDaughter()
{
//Once
Activator new HotDaughter();
//Message
Message "I ;
}
}
|
这里还是利用了将Lambda表达式作为属性,可以随时重新赋值的特点。当然这只是一个简单的示例,真实项目中并不建议大家这么去做。
方法字典
实际上这个模式我们在上一篇的返回方法中已经讲到了,只是没有这样一个名字而已,就算是一个总结吧。故事是这样的,你是不是经常会写到switch-case语句的时候觉得不够优雅?但是你又不想去整个什么工厂模式或者策略模式,那怎么样让你的代码看起来高级一点呢?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
public Action string input)
{
switch
{
case "random" :
return () /* };
case "dynamic" :
return () /* };
default :
return () /* };
}
}
//-------------------变身之后-----------------------
Dictionary< string ,
public void BuildFinalizers()
{
finalizers new Dictionary< string ,
finalizers.Add( "random" , /* });
finalizers.Add( "dynamic" , /* });
}
public Action string input)
{
if (finalizers.ContainsKey(input))
return finalizers[input];
return () /* };
}
|
好像看起来是不一样了,有那么一点味道。但是一想是所有的方法都要放到那个BuildFinalizers里面,这种组织方法实在是难以接受,我们来学学插件开发的方式,让它自己去找所有我们需要的方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
static Dictionary< string ,
//
public static void BuildFinalizers()
{
finalizers new Dictionary< string ,
//
var types
foreach ( var type in types)
{
//
if (type.IsSubclassOf( typeof (MyMotherClass)))
{
//
var m
//
if (m null )
{
var instance null ) as MyMotherClass;
var name "Mother" );
var method
finalizers.Add(name,
}
}
}
}
public Action string input)
{
if (finalizers.ContainsKey(input))
return finalizers[input];
return () /* };
}
|
如果要实现插件化的话,我们不光要能够加载本程序集下的方法,还要能随时甚至运行时去加载外部的方法,请继续往下看:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
internal static void BuildInitialFinalizers()
{
finalizers new Dictionary< string ,
LoadPlugin(Assembly.GetExecutingAssembly());
}
public static void LoadPlugin(Assembly
{
var types
foreach ( var type in types)
{
if (type.IsSubclassOf( typeof (MyMotherClass)))
{
var m
if (m null )
{
var instance null ) as MyMotherClass;
var name "Mother" );
var method
finalizers.Add(name,
}
}
}
}
|
现在,我们就可以用这个方法,给它指定程序集去加载我们需要的东西了。
最后留给大家一个问题,我们能写递归表达式么?下面的方法如果用表达式如何写呢?
1
2
3
4
5
6
7
|
int factorial( int n)
{
if (n
return 1;
else
return n
}
|