学习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;
};
}
如他所言,这确实是个笨方法,如果有合适的方法,希望联系我。这个类问题老多了,拓展性,可维护都很糟。
现在发现建立个良好的类还是有相当的难度,不仅需要充分考虑当前需要实现的功能,也要考虑将来可能需要拓展的功能,对上兼容,对下拓展,良好的结构,精简的代码。