上一篇 背后的故事之 – 快樂(lè)的Lambda表達(dá)式(一)我們由淺入深的分析了一下Lambda表達(dá)式。知道了它和委托以及普通方法的區(qū)別,并且通過(guò)測(cè)試對(duì)比他們之間的性能,然后我們通過(guò)IL代碼深入了解了Lambda表達(dá)式,以及介紹了如何在.NET中用Lambda表達(dá)式來(lái)實(shí)現(xiàn)JavaScript中流行的一些模式。
今天,我們接著來(lái)看Lambda表達(dá)式在.NET中還有哪些新鮮的玩法。
Lambda表達(dá)式玩轉(zhuǎn)多態(tài)
Lambda如何實(shí)現(xiàn)多態(tài)?我們用抽象類和虛方法了,為什么還要用Lambda這個(gè)玩意?且看下面的代碼:
class MyBaseClass
{
public Action SomeAction { get; protected set; }
public MyBaseClass()
{
SomeAction = () =>
{
//Do something!
};
}
}
class MyInheritedClass : MyBaseClass
{
public MyInheritedClass()
{
SomeAction = () => {
//Do something different!
};
}
}
我們的基類不是抽象類,也沒(méi)有虛方法,但是把屬性通過(guò)委托的方式暴露出來(lái),然后在子類中重新為我們的SomeAction賦予一個(gè)新的表達(dá)式。這就是我們實(shí)現(xiàn)多態(tài)的過(guò)程,當(dāng)然父類中的SomeAction的set有protected的保護(hù)級(jí)別,不然就會(huì)被外部隨易修改了。但是這還不完美,父類的SomeAction在子類中被覆蓋之后,我們徹底訪問(wèn)不到它了,要知道真實(shí)情況是我們可以通過(guò)base來(lái)訪問(wèn)父類原來(lái)的方法的。接下來(lái)就是實(shí)現(xiàn)這個(gè)了
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!
};
}
}
上面的代碼中,我們通過(guò)AddSomeAction來(lái)實(shí)現(xiàn)覆蓋的同時(shí),將原來(lái)的方法保存在previousActions中。這樣我們就可以保持兩者同時(shí)存在了。
大家知道子類是不能覆蓋父類的靜態(tài)方法的,但是假設(shè)我們想實(shí)現(xiàn)靜態(tài)方法的覆蓋呢?
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表達(dá)式作為屬性,可以隨時(shí)重新賦值的特點(diǎn)。當(dāng)然這只是一個(gè)簡(jiǎn)單的示例,真實(shí)項(xiàng)目中并不建議大家這么去做。
方法字典
實(shí)際上這個(gè)模式我們?cè)谏弦黄姆祷胤椒ㄖ幸呀?jīng)講到了,只是沒(méi)有這樣一個(gè)名字而已,就算是一個(gè)總結(jié)吧。故事是這樣的,你是不是經(jīng)常會(huì)寫(xiě)到switch-case語(yǔ)句的時(shí)候覺(jué)得不夠優(yōu)雅?但是你又不想去整個(gè)什么工廠模式或者策略模式,那怎么樣讓你的代碼看起來(lái)高級(jí)一點(diǎn)呢?
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 () => { /* ... */ };
}
好像看起來(lái)是不一樣了,有那么一點(diǎn)味道。但是一想是所有的方法都要放到那個(gè)BuildFinalizers里面,這種組織方法實(shí)在是難以接受,我們來(lái)學(xué)學(xué)插件開(kāi)發(fā)的方式,讓它自己去找所有我們需要的方法。
static Dictionary<string, Action> finalizers;
// 在靜態(tài)的構(gòu)造函數(shù)用調(diào)用這個(gè)方法
public static void BuildFinalizers()
{
finalizers = new Dictionary<string, Action>();
// 獲得當(dāng)前運(yùn)行程序集下所有的類型
var types = Assembly.GetExecutingAssembly().GetTypes();
foreach(var type in types)
{
// 檢查類型,我們可以提前定義接口或抽象類
if(type.IsSubclassOf(typeof(MyMotherClass)))
{
// 獲得默認(rèn)無(wú)參構(gòu)造函數(shù)
var m = type.GetConstructor(Type.EmptyTypes);
// 調(diào)用這個(gè)默認(rèn)的無(wú)參構(gòu)造函數(shù)
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 () => { /* ... */ };
}
如果要實(shí)現(xiàn)插件化的話,我們不光要能夠加載本程序集下的方法,還要能隨時(shí)甚至運(yùn)行時(shí)去加載外部的方法,請(qǐng)繼續(xù)往下看:
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);
}
}
}
}
現(xiàn)在,我們就可以用這個(gè)方法,給它指定程序集去加載我們需要的東西了。
最后留給大家一個(gè)問(wèn)題,我們能寫(xiě)遞歸表達(dá)式么?下面的方法如果用表達(dá)式如何寫(xiě)呢?
int factorial(int n)
{
if(n == 0)
return 1;
else
return n * factorial(n - 1);
}
更多信息請(qǐng)查看IT技術(shù)專欄