日期:2014-06-10  浏览次数:20687 次

前言

  泛型并不是C#语言一开始就带有的特性,而是在FCL2.0之后实现的新功能。基于泛型,我们得以将类型参数化,以便更大范围地进行代码复用。同时,它减少了泛型类及泛型方法中的转型,确保了类型安全。委托本身是一种引用类型,它保存的也是托管堆中对象的引用,只不过这个引用比较特殊,它是对方法的引用。事件本身也是委托,它是委托组,C#中提供了关键字event来对事件进行特别区分。一旦我们开始编写稍微复杂的C#代码,就肯定离不开泛型、委托和事件。本章将针对这三个方面进行说明。

本文已更新至http://www.cnblogs.com/aehyok/p/3624579.html 。本文主要学习记录以下内容:

  建议35、使用default为泛型类型指定初始值

  建议36、使用FCL中的委托声明

  建议37、使用lambda表达式代替方法和匿名方法

建议35、使用default为泛型类型指定初始值

  有些算法,比如泛型集合List<T>的Find算法,所查找的对象有可能会是值类型,也有可能是引用类型。在这种算法内部,我们常常会为这些值类型变量或引用类型变量指定默认值。于是,问题来了:值类型变来那个的默认初始值是0值,而引用类型变量的默认初始值是null值,显然,这会导致下面编译出错:

C#编译器会阻止这样的代码通过编译。要让编译器接收为一个泛型类型参数指定一个初始值,最妥当的办法就是使用default关键字。所以,在上面的代码应该改为:

        public T Func<T>()
        {
            T t = default(T);
            return t;
        }

这样如果它在运行时碰到的T是一个整型,那么运行时会为其赋值0;如果T在运行时是一个Person这样的引用类型,则会为其赋null值。

建议36、使用FCL中的委托声明

 要注意FCL中存在三类这样的委托声明,他们分别是:Action、Func、Predicate。尤其是在他们的泛型版本出来以后,已经能够满足我们在实际编码过程中的大部分需要。

这里是之前一篇关于Action、Func、Predicate的有关介绍http://www.cnblogs.com/aehyok/p/3382291.html

除了Action、Func、Predicate外,FCL中还有用于标识特殊含义的委托声明。如用于表示注册事件方法的委托声明:

public delegate void EventHandler(object sender,EventArgs e);

public delegate void EnentHandler<TEventArgs>(object sender,TEventArgs e);

表示线程的委托声明:

public delegate void ThreadStart();

public delegate void ParameterizedThreadStart(object obj);

表示异步回调的委托声明:

public delegate void AsyncCallback(IAsyncResult ar);

在FCL中没一类委托声明都代表一类特殊的用途,虽然可以使用自己的委托声明来代替,但是这样做不仅没有必要,而且会让代码失去简洁性和标准型。在我们实现自己的委托声明前,应该首先查看MSDN,确信有必要之后才这样做。

建议37、使用lambda表达式代替方法和匿名方法

首先我们使用Action和Func来做一个简单的小例子,控制台应用程序代码如下所示:

第一个版本

    class Program
    {
        static int Add(int i, int j)
        {
            return i + j;
        }

        static void Print(string message)
        {
            Console.WriteLine(message);
        }

        static void Main(string[] args)
        {
            Func<int, int, int> add = Add;
            Action<string> print = Print;
            print(add(4, 5).ToString());
            Console.ReadLine();
        }
    }

实际上要完成上面的功能,还有多种编码方式,先来看一种最中规中矩的方式,同时也是最繁琐的写法:

第二个版本

    class Program
    {
        static int Add(int i, int j)
        {
            return i + j;
        }

        static void Print(string message)
        {
            Console.WriteLine(message);
        }

        static void Main(string[] args)
        {
            Func<int, int, int> add = new Func<int,int,int>(Add);
            Action<string> print =new Action<string>(Print);
            print(add(4, 5).ToString());
            Console.ReadLine();
        }
    }

其实也就是将第一个版本稍作调整。从上面的写法中也可以看出:Add方法和Print方法实际上都只有一条语句,因此,使用匿名方法也许是一种更好的选择:

第三个版本

        static void Main(string[] args)
        {
            Func<int, int, int> add = new Func<int,int,int>(delegate(int i,int j)
                {
                    return i+j;
                });
            Action<string> print =new Action<string>(delegate(string message)
                {
                    Console.WriteLine(message);
                });
            print(add(4, 5).ToString());
            Console.ReadLine();
        }

使用匿名方法以后,我们不需要在Main方法外部声明两个方法了,可以直接在Main这个工作方法中完成所有的代码编写,而且不会影响代码清晰性。实际上,所有代码行数不超过3行的方法(条件是它不倍重用),我们都建议采用这种方式来编写。上面的版本继续改进:

第四个版本

        static void Main(string[] args)
        {
            Func<int, int, int> add = delegate(int i,int j)
                {
                    return i+j;
                };
            Action<string> print =delegate(string message)
                {
                    Console.WriteLine(message);
                };
            print(add(4, 5).ToString());
            Console.ReadLine();
        }

以上代码看上去更简化了,不过,最终极的改进是使用lambda表达式:

第五个版本

        static void Main(string[] args)
        {
            Func<int, int, int> add = (x, y) => x + y;
            Action<string> print = (message) => Console.WriteLine(message);
            print(add(4, 5).ToString());
            Console.ReadLine();
        }

Lambda表达式操作符”=>“的左侧是方法的参数,右侧是方法体,其本质是匿名方法。实际上,经过编译后Lambda表达式就是一个匿名方法。我们应该在实际的编码工作中熟练运用它,避免写出繁琐且不美观的代码。