委托,不知道你是否有也这样理解(二)

目录

  • 泛型委托
  • 简化语法
  • 委托与反射

相关文章链接:

事件,你是否也这样理解 

http://www.cnblogs.com/sunchong/p/sunchong.html

委托,你是否也这样理解(一)

http://www.cnblogs.com/sunchong/p/3480612.html

 

一、泛型委托

我们知道泛型能够提高效率,避免代码重复,灵活。

 

C#提供了无返回值的泛型委托Action

public delegate void Action<in T>(T obj);

从上我们看到,输入参数是obj,无返回值。T是泛型占位符,输入参数类型并可以协变。

像这样的委托c#为我们提供了16个,可以传递1~16个输入参数。

 

C#也提供了有返回值的泛型委托Func

public delegate TResult Func<in T, out TResult>(T arg);

可以协变的输入参数arg,逆变的返回参数TResult。

这样的泛型委托也是16个,也可以传递1~16个输入参数。外加一个返回参数。返回参数类型位于泛型占位符<in T,inT1,in T2,...,out TResult>最后一个参数TResult。

 

二、简化语法

1、使用ThreadPool

 public void PutMsg()
{
            System.Threading.ThreadPool.QueueUserWorkItem(DelegateTest.PutMsg,"K1");
}

细看一下定义:

public static bool QueueUserWorkItem(WaitCallback callBack, object state);
public delegate void WaitCallback(object state);

很显然,WaitCallback是一个又一个输入参数并无返回值的委托,而参数state就是方法需要传入的参数。

这样的方式有局限性,因为必须是一个输入参数并无返回值。

 

、使用Lambda表达式

 public void PutMsg()
{
           System.Threading.ThreadPool.QueueUserWorkItem(msg=>Console.WriteLine(msg.ToString()),"K1");
}

编译器会为我们自动创建一个私有方法,这个方法名我们不会知道,因为编译器会根据他自己的规则自动生成。

我们也会将这样的方法称之为匿名方法。传递一个Object类型的参数,在=>后面的就是方法体。通过IL就会看到生成的代码。。

[CompilerGenerated]
private static void <PutMsg>b__0(object msg)
{
    Console.WriteLine(msg.ToString());
}

 

上面就是自己本地的IL代码,我们可以看到我们之前定义的msg和=>的方法体。此外还有一个特性[CompilerGenerated],这说明此特性是编译器生成的代码,不是我们自己写的。

 

四、局部变量无需包装到类中就可以传递给回调方法

 public class AClass
    {
        public static void UsingLocalVariablesInTheCallbackCode(Int32 numToDo)
        {
            Int32[] squares = new Int32[numToDo];
            System.Threading.AutoResetEvent done = new System.Threading.AutoResetEvent(false);
            for (int n = 0; n < squares.Length; n++)
            {
                System.Threading.ThreadPool.QueueUserWorkItem(obj =>
                {
                    int num = (int)obj;
                    squares[num] = num * num;
                    if (System.Threading.Interlocked.Decrement(ref numToDo) == 0)
                    {
                        done.Set();
                    }
                },
                n);
            }
            done.WaitOne();
        }
    }

首先大体分析一下,在这个方法中,有一个参数:numToDo,两个局部变量:squares,done。关键是下面这个Lambda方式的回调函数,而我们知道使用Lambda就类似又构造一个方法。现在的问题是,通过Lamdba方式生成的方法引用了在UsingLocalVariablesInTheCallbackCode(Int32 numToDo)方法定义的局部变量。我们知道同一个类中的两个方法,一个方法无法直接引用另一个方法的局部变量。那为什么以上可以直接引用?而且还让我们感觉用得理所当然。好吧,编译器确实又为我们做了很多工作,如果我们想让一个方法引用到另一方法中的局部变量,那就将这些局部变量打包到一个类中,通过传递此类对参数进行赋值和取值。

 

四、委托与反射

一般情况下我们会知道回到函数的参数个数和类型,但是如果我们不确定这些,那就通过反射让编译器来生成我们所需要的。

C#的Delete类为我们提供了委托反射(下面只是其中一个),通过传递委托类型和注册的方法名,对方法进行注册。

public static Delegate CreateDelegate(Type type, MethodInfo method);

通过DynamicInvoke来进行调用。

public object DynamicInvoke(params object[] args);

 

posted @ 2015-04-26 23:44  K战神  阅读(1084)  评论(2编辑  收藏  举报