学习c#匿名类的时候,写demo,开始只是两句code,后来一些想法逐步在我的脑海中出现,把这些想法写下来,一方面是见证自己的进步,另一方面也与大家分享如何写一个“优雅”的程序。
class Program { public delegate void say(object word); public delegate int Add(int x, int y); public delegate int Sub(int x, int y); public delegate int Mul(int x, int y); public delegate int Div(int x, int y); static void Main(string[] args) { say sayResult = delegate(object word) { Console.WriteLine(word); }; Add add = delegate(int x, int y) { return x + y; }; Sub sub = delegate(int x, int y) { return x - y; }; Mul mul = delegate(int x, int y) { return x * y; }; Div div = delegate(int x, int y) { return x / y; }; sayResult(add(5,6)); sayResult(sub(5,6)); sayResult(mul(5,6)); sayResult(div(5,6)); } }
作为一段代码,最基本的职能就是要完成功能。在这几句代码中简单的运用了匿名对象实现了加,减,乘,除的运算。但是看上去这段代码有很多相似的语句,在各方面都有很大的提升余地,首先就拿那5个委托开刀,观察4个委托的形式,有相同的签名,相同的返回类型。C#提供了一些做好的委托类型(Action,Func),事实上并不需要我去定义什么。
Action<object> sayResult = delegate(object word) { Console.WriteLine(word); }; Func<int, int, int> add = delegate(int x, int y) { return x + y; }; Func<int, int, int> sub = delegate(int x, int y) { return x - y; }; Func<int, int, int> mul = delegate(int x, int y) { return x * y; }; Func<int, int, int> div = delegate(int x, int y) { return x / y; }; sayResult(add(5,6)); sayResult(sub(5,6)); sayResult(mul(5,6)); sayResult(div(5,6));
这样在代码量上面就可以少了5行,但是4个匿名函数在形式和功能上都有一定的相关性,思考集成这4和匿名函数。
这是我开始的想法:
List<Func<int, int, int>> Caculate = new List<Func<int, int, int>>(); Caculate.AddRange(new Func<int, int, int>[] { add, sub, mul, div }); sayResult(Caculate[0](5, 6));
很明显代码的长度增加了,多了新的数据成员,在对效率要求不是那么严格的代码中,牺牲代码的长度来换取更好的结构,我认为还是很划算的。但是list中的索引方式不便于使用,假如这个程序集被引用,并不能从单纯的数字上看出什么来。严格的顺序也会增加出错的几率。因此,修改后的代码是这样的:
Dictionary<string, Func<int, int, int>> Cacular = new Dictionary<string, Func<int, int, int>>(); Cacular.Add("add", add); Cacular.Add("sub", sub); Cacular.Add("mul", mul); Cacular.Add("div", div); sayResult(Cacular["add"](5, 6));
代码再度加长,Dictionary并没提供addrange这种方法。如果需要拓展更多的操作,可以为Dictionary扩展方法addrange来获取更好的可读性。鉴于这是个demo,并未做这方面的工作,现在可以获得更好的集成和可读。说到集成,还有什么能比class更加引人注目呢?Dictionary在这方面太乏力了,首先在代码量上做出了让步,也不能提供智能提示的支持,依旧需要相关的文档支持,才能明晓“键”的含义。是时候将它升格成类了。
public static class Caculate { public static Func<int, int, int> add = delegate(int x, int y) { return x + y; }; public static Func<int, int, int> sub = delegate(int x, int y) { return x - y; }; public static Func<int, int, int> mul = delegate(int x, int y) { return x * y; }; public static Func<int, int, int> div = delegate(int x, int y) { return x / y; }; }
这里我把运算这4个操作放到caculate类中sayResult独立出去,因为它们并不没有紧密的关系,我又想让这个类 能够支持更多的数据类型,
public static class Caculate<T> { public static Func<T, T, T> add = delegate(T x, T y) { return x + y; }; public static Func<T, T, T> sub = delegate(T x, T y) { return x - y; }; public static Func<T, T, T> mul = delegate(T x, T y) { return x * y; }; public static Func<T, T, T> div = delegate(T x, T y) { return x / y; }; }
能这样写多好,可惜泛型不能用于运算符。通过百度获得一个类似的实现。
public static class Cacular<T> where T : struct { public static Func<T, T, T> add = delegate(T x, T y) { T result = default(T); Type type = x.GetType(); string s = type.ToString(); switch (type.ToString()) { default: break; case "System.Int32": result= (T)(object)((Int32)(object)x + (Int32)(object)y); break; case "System.Single": result = (T)(object)((Single)(object)x + (Single)(object)y); break; case "System.Double": result = (T)(object)((double)(object)x + (double)(object)y); break; } return result; }; public static Func<T, T, T> sub = delegate(T x, T y) { T result = default(T); Type type = x.GetType(); switch (type.ToString()) { default: break; case "System.Int32": result = (T)(object)((Int32)(object)x - (Int32)(object)y); break; case "System.Single": result = (T)(object)((Single)(object)x - (Single)(object)y); break; case "System.Double": result = (T)(object)((double)(object)x - (double)(object)y); break; } return result; }; public static Func<T, T, T> mul = delegate(T x, T y) { T result = default(T); Type type = x.GetType(); switch (type.ToString()) { default: break; case "System.Int32": result = (T)(object)((Int32)(object)x * (Int32)(object)y); break; case "System.Single": result = (T)(object)((Single)(object)x * (Single)(object)y); break; case "System.Double": result = (T)(object)((double)(object)x * (double)(object)y); break; } return result; }; public static Func<T, T, T> div = delegate(T x, T y) { T result = default(T); Type type = x.GetType(); switch (type.ToString()) { default: break; case "System.Int32": result = (T)(object)((Int32)(object)x / (Int32)(object)y); break; case "System.Single": result = (T)(object)((Single)(object)x / (Single)(object)y); break; case "System.Double": result = (T)(object)((double)(object)x / (double)(object)y); break; } return result; }; }
如他所言,这确实是个笨方法,如果有合适的方法,希望联系我。这个类问题老多了,拓展性,可维护都很糟。
现在发现建立个良好的类还是有相当的难度,不仅需要充分考虑当前需要实现的功能,也要考虑将来可能需要拓展的功能,对上兼容,对下拓展,良好的结构,精简的代码。