关于C#中Anonymous Method---匿名方法的基础知识

Anonymous Method--匿名方法说的是不对方法进行显式定义而将方法的执行代码直接封装到Delegate对象中,这样做的好处不仅仅是简化代码这么简单,它还可以帮助你进行多个方法间的状态共享和将代码段作为参数进行传递。

一、Anonymous Method初探

下面看一个不使用Anonymous Method的例子:

using System;

using System.Collections.Generic;

using  System.Windows.Forms;

namespace  Anonymous_Method
{
    
static   class  Program
    {
        
///   <summary>
        
///  应用程序的主入口点。
        
///   </summary>
        [STAThread]
        
static   void  Main()
        {
            String[] names 
= " Jeff " " Kristin " " Adian "  };
            names 
=  Array.FindAll(names,  new  Predicate < String > (NamePredicate));          
            names 
=  Array.ConvertAll < String, String > (names,  new  Converter < String,String > (NameConvertPredicate));
            Array.Sort(names, String.Compare);
            Array.ForEach(names, Console.WriteLine);

            Console.ReadKey();
        }

        
///   <summary>
        
///  Predicates the specified name.
        
///   </summary>
        
///   <param name="name"> The name. </param>
        
///   <returns> true or false </returns>
         static  Boolean NamePredicate(String name)
        {
            
return  name.IndexOf( ' i ' >=   0 ;
        }

        
///   <summary>
        
///  Names the convert predicate.
        
///   </summary>
        
///   <param name="name"> The name. </param>
        
///   <returns> String </returns>
         static  String NameConvertPredicate(String name)
        {
            
return  name.ToUpper();
        }
    }
}

其中Array.FindAll原型为:

                public static T[] FindAll<T>(T[] array, Predicate<T> match);

    Predicate是一个delegate,表示定义一组条件并确定指定对象是否符合这些条件的方法。原型为:

                public delegate bool Predicate<T>(T obj);

    Array.ConvertAll原型为:

                public static TOutput[] ConvertAll<TInput, TOutput>(TInput[] array, Converter<TInput, TOutput> converter);

    Converter<TInput, TOutput>是一个delegate,表示将对象从一种类型转换为另一种类型的方法。原型为:

                public delegate TOutput Converter<TInput, TOutput>(TInput input);

        如果像 Array.FindAll 这样的方法用到多次,比如我接下来要在 names 中查找字符 'K' ,那么就需要再写一个类似 NamePredicate 的命名方法,可以想象这将是多么郁闷的一件事情,这时我们可以利用 Anonymous Method 来简化编码提高生产率,代码如下:

using System;
using System.Collections.Generic;
using System.Windows.Forms;

namespace Anonymous_Method
{
    
static class Program
    {
        
/// <summary>
        
/// 应用程序的主入口点。
        
/// </summary>
        [STAThread]
        
static void Main()
        {
            String[] names 
="Jeff""Kristin""Adian" };

            Char charToFind 
= 'i';
            names 
= Array.FindAll(names, delegate(String name) { return name.IndexOf(charToFind) >= 0; });
            names 
= Array.ConvertAll<String, String>(names, delegate(String name) { return name.ToUpper(); });
            Array.Sort(names, String.Compare);
            Array.ForEach(names, Console.WriteLine);

            Console.ReadKey();
        }
    }
}

 

Anonymous Method好处显而易见,当然,我认为在方法的代码行数不多的情况下使用Anonymous Method比较合适。

二、深入了解Delegate类

Delegate类是一个抽象类,delegate关键字定义的类型都属于Delegate类的非抽象派生类,Delegate类的定义如下:

[Serializable, ClassInterface(ClassInterfaceType.AutoDual)]
public   abstract   class  Delegate : ICloneable, ISerializable
{
    
//  Fields
     private  RuntimeMethodInfo _method;
    
private  IntPtr _methodPtr;
    
private  IntPtr _methodPtrAux;
    
private   object  _target;

    
//  Methods
     private  Delegate();
    
protected  Delegate( object  target,  string  method);
    
protected  Delegate(Type target,  string  method);
    
public   virtual   object  Clone();
    
public   static  Delegate Combine(Delegate[] delegates);
    
public   static  Delegate Combine(Delegate a, Delegate b);
    
protected   virtual  Delegate CombineImpl(Delegate d);
    
public   static  Delegate CreateDelegate(Type type, MethodInfo method);
    
public   static  Delegate CreateDelegate(Type type,  object  target,  string  method);
    
public   static  Delegate CreateDelegate(Type type, Type target,  string  method);
    
public   static  Delegate CreateDelegate(Type type,  object  target,  string  method,  bool  ignoreCase);
    
public   object  DynamicInvoke( object [] args);
    
protected   virtual   object  DynamicInvokeImpl( object [] args);
    
public   override   bool  Equals( object  obj);
    
public   override   int  GetHashCode();
    
public   virtual  Delegate[] GetInvocationList();
    
protected   virtual  MethodInfo GetMethodImpl();
    
public   virtual   void  GetObjectData(SerializationInfo info, StreamingContext context);
    [MethodImpl(MethodImplOptions.InternalCall)]
    
private   static   extern  Delegate InternalAlloc(RuntimeType type);
    [MethodImpl(MethodImplOptions.InternalCall)]
    
internal   extern   void  InternalCreate( object  target,  string  method,  bool  ignoreCase);
    [MethodImpl(MethodImplOptions.InternalCall)]
    
internal   extern   void  InternalCreateMethod(RuntimeMethodInfo invokeMeth, RuntimeMethodInfo targetMethod);
    [MethodImpl(MethodImplOptions.InternalCall)]
    
internal   extern   void  InternalCreateStatic(RuntimeType target,  string  method);
    [MethodImpl(MethodImplOptions.InternalCall)]
    
internal   extern  RuntimeMethodInfo InternalFindMethodInfo();
    
private   bool  IsStatic();
    
public   static   bool   operator   == (Delegate d1, Delegate d2);
    
public   static   bool   operator   != (Delegate d1, Delegate d2);
    
public   static  Delegate Remove(Delegate source, Delegate value);
    
public   static  Delegate RemoveAll(Delegate source, Delegate value);
    
protected   virtual  Delegate RemoveImpl(Delegate d);

    
//  Properties
     public  MethodInfo Method {  get ; }
    
public   object  Target {  get ; }
}

 

 

对于delegate关键字定义的类型,其实例的创建方式有3种:

1、利用new关键字来实现,如上例中的new Predicate<String>(NamePredicate);要求所封装方法的签名与delegate类型一致。

2、Anonymous Method,如上例中的 names = Array.FindAll(names, delegate(String name) {  return name.IndexOf(charToFind) >= 0;  });

要求所封要求参数列表和执行代码的返回类型与delegate类型保持一致。

3、较少用,通过Delegate类提供的静态方法CreateDelegate来创建。

Delegate类提供了两个公共只读属性:Target和Method,分别代表调用方法的对象和所封装的方法,对于Named Method,其Target属性值为调用方法的当前对象,Method属性值为实例化delegate对象时指定的方法;当方法为静态时,Target属性值为null。对于Anonymous Method,其Target属性值始终为null,Method属性值为赋值给delegate对象的匿名方法所创建的方法。

当我们定义一个delegate类型的时候,如: public delegate bool Predicate<T>(T obj);编译器其实会将它编译为像下面的一个类:

public   class  Predicate < T >  : System.MulticastDelegate
{
        
public  Predicate(Object @object, IntPtr method);

        
public   virtual  IAsyncResult BeginInvoke(T obj, AsyncCallback callback, Object @object);

        
public   virtual  Boolean EndInvoke(IAsyncResult result);

        
public   virtual  Boolean Invoke(T obj);

}

 

可以看到该类继承于FCL中定义的System.MulticastDelegate类,而System.MulticastDelegate又继承于Delegate类,所有delegate类都是继承于System.MulticastDelegate类的。想更为深入了解delegate可以参考Jeffrey Richter的大作:《CLR.via.C#.Second.Edition》。

三、Anonymous Method的定义规则

  Anonymous Method由3个部分组成:关键字delegate,parameters列表和code section,其中parameters可以省略。

Anonymous Method表达式本身不能成为一个完整的语句,需要将它赋值给一个delegate对象,而且要求Anonymous Method表达式与delegate的定义一致:Anonymous Method返回类型和delegate定义类型相同或者可以隐式转换为delegate定义类型的返回类型;Anonymous Method的参数列表可以省略,但是如果有out参数则不能省略;如果Anonymous Method表达式指定了参数列表,则参数列表要与delegate定义类型的参数列表相同,且每个参数的类型与delegate中对应的类型要相同或者可以隐式转换;Anonymous Method表达式参数列表中不能有params所修饰的数组型参数。需要注意省略参数列表和参数列表为空时两个完全不同的概念。

四、Anonymous Method的外部变量

Anonymous Method表达式所在代码段中出现的所有变量。如下:

using  System;
using  System.Collections.Generic;
using  System.Windows.Forms;

namespace  Anonymous_Method
{
    
public   delegate  Int32 SubDelegate(Int32 x);

    
static   class  Program
    {
        
///   <summary>
        
///  应用程序的主入口点。
        
///   </summary>
        [STAThread]
        
static   void  Main()
        {
            Int32 x 
=   5 ;
            
// Named Method
            SubDelegate d1  =   new  SubDelegate(Sub);
            Console.Write(d1(x));
            Console.Write(x);
            Console.Write(d1(x));
            Console.WriteLine(x);

            SubDelegate d2 
=   delegate  {  return  x -- ; };
            Console.Write(d2(x));
            Console.Write(x);
            Console.Write(d2(x));
            Console.WriteLine(x);

            Console.ReadKey();
        }

        
///   <summary>
        
///  Subs the specified x.
        
///   </summary>
        
///   <param name="x"> The x. </param>
        
///   <returns></returns>
         static  Int32 Sub(Int32 x)
        {
            
return  x -- ;
        }
    }
}

 

这里x就是外部变量,上面代码的输出为:5555

                                   5443 

      另外需要注意的就是外部变量要想在Anonymous Method中使用就必须是已经赋值的。由此可见多个方法可以通过外部变量来进行状态共享和消息传递。

      此外Anonymous Method还能作为方法参数和返回值,在event中也可以使用Anonymous Method。

五、总结

      Anonymous Method所带来的最大优越性就是可以将一段代码直接作为参数来使用而不用显式的去定义一个方法,可以简化代码,提高工作效率,根据Jeffrey Richter的经验,Anonymous Method中应该包含3行以内的代码。Anonymous Method的其他用途还望各大高手补充。


 

 

 

转载于:https://www.cnblogs.com/vivounicorn/archive/2009/05/08/1452676.html

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值