c# 扩展方法奇思妙用滥用篇一:改进 2011 年最佳代码
2011-08-08 18:39 by 鹤冲天, 2219 visits, 收藏, 编辑
今天从老赵 的文章《谈谈年度最佳代码“不管你们信不信,反正我信了”》中学习了 2011 年最佳代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
try { if (you.believe(it) || !you.believe(it)) { I.believe(it); } } catch (Exception ex) { throw new Exception("It's a miracle!"); } finally { it.justHappened(); } |
老赵 在文中强调了语义编程,建议大家去看看。
在我看来,第三行代码可以改进一些。
信不信,引申出来听不听、做不做、想不想,隐约中有”或者不”的意味,于是 OrNot 扩展方法在我大脑中出现了。
不过下手之前,还得准备一下:
准备工作
先来准备两个接口,表示上面代码中 you、I、it:
1 2 3 4 5 6 7 8 9 |
public interface IPerson { bool Believe(IThing thing); } public interface IThing { void JustHappened(); } |
这三个变量可如下声明:
1 2 3 |
IThing it = null; IPerson you = null; IPerson I = null; |
OrNot 扩展方法
我最初的想法是,既然是个扩展,就应该让它应用尽量广泛,于是写出的下面的泛型扩展:
1 2 3 4 5 6 7 |
public static class Extensions { public static bool OrNot<T>(this Predicate<T> predicate, T t) { return predicate(t) || !predicate(t); } } |
不过用起来不方便,如把代码写成下面的样子,是编译不通过的:
1 2 3 4 |
if(you.Believe.OrNot(it)) { I.Believe(it); } |
提示错误:
'IPerson.Believe(IThing)' is a 'method', which is not valid in the given context
只好写成为:
1 2 3 4 5 |
Predicate<IThing> youBelieve = you.Believe;
if(youBelieve.OrNot(it))
{
I.Believe(it);
}
|
或者:
1 2 3 4 |
if (((Predicate<IThing>)you.Believe).OrNot(it))
{
I.Believe(it);
}
|
这两种方式我都看不上眼,不过第二种方式给了一些灵感,于是做了些改进。
改进
上面代码使用了 Predicate<T> 委托,代表输入一个 T 返回一个布尔值。
在本应用中,是输入一个 IThing 返回一个布尔值,可表示为 Predicate<IThing>,写起来太烦索了。
何不就当前语境定义一个新的委托呢?如下:
1
|
public delegate bool WhatEver (IThing obj); |
相应扩展方法修改为:
1 2 3 4 5 6 7 |
public static class Extensions { public static bool OrNot(this WhatEver func, IThing t) { return func(t) || !func(t); } } |
代码可写成:
1 2 3 4 |
if (((WhatEver)you.Believe).OrNot (it)) { I.Believe(it); } |
准确的的表达出了”不管你们信不信“的意思。
完整代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
try { if (((WhatEver)you.Believe).OrNot(it)) { I.Believe(it); } } catch (Exception ex) { throw new Exception("It's a miracle!"); } finally { it.JustHappened(); } |
再次改进
回复中有朋友问是否可写成 ((WhatEver)you.Believe(it).OrNot(),读起来顺多了。
这样可能不恰当,写成如下道是可以的:
1 2 3 4 |
if (whatEver(you.Believe)(it).OrNot()) { I.Believe(it); } |
这时 whatEver 是个静态变量:
1
|
public static Func<Predicate<IThing>, Func<IThing, Func<bool>>> whatEver = p => i => (() => p(i)); |
这种方式在我的文章《借助委托精简代码》中有提及。
配合如下扩展方法:
1 2 3 4 5 6 7 |
public static class Extensions { public static bool OrNot(this Func<bool> func) { return func() || !func(); } } |
完整代码如下:
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 |
namespace ImproveBestCodeOf2011 { class Program { public static Func<Predicate<IThing>, Func<IThing, Func<bool>>> whatEver = p => i => (() => p(i)); static void Main(string[] args) { IThing it = null; IPerson you = null; IPerson I = null; if (whatEver(you.Believe)(it).OrNot()) { I.Believe(it); } } } public static class Extensions { public static bool OrNot(this Func<bool> func) { return func() || !func(); } } public interface IPerson { bool Believe(IThing thing); } public interface IThing { void JustHappened(); } } |
呵!这种方式又滥用了委托!
小结
使用一段代码结束本文(可跳过):
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 39 40 41 42 43 44 45 46 47 |
static void Main(string[] args) { IThing it = new OrNotExtensionIsTheBestOf2011(); IPerson you = new Person { Name = "看本文的你" }; IPerson I = new Person { Name = "鹤冲天" }; if (((WhatEver)you.Believe).OrNot(it)) { I.Believe(it); } //or if (whatEver(you.Believe)(it).OrNot()) { I.Believe(it); } } public class OrNotExtensionIsTheBestOf2011: IThing { public string Title { get { return "OrNot 扩展方法是 2011 年最佳扩展"; } } public void JustHappened() { Console.WriteLine("OrNot 扩展方法被评为 2011 年最佳扩展"); } } public class Person : IPerson { public string Name { get; set; } public bool Believe(IThing thing) { if(thing is OrNotExtensionIsTheBestOf2011) { var theBest = thing as OrNotExtensionIsTheBestOf2011; Console.WriteLine("支持 {0}", theBest.Title); Console.WriteLine("推荐 {0}", theBest.Title); return true; } throw new NotImplementedException(); } } |
输出:
本文说笑,且莫当真。
滥用扩展方法,切务模仿!
-------------------
思想火花,照亮世界