委托的杂七杂八---《clr via c#》笔记
2012-01-31 22:35 海不是蓝 阅读(471) 评论(0) 编辑 收藏 举报
初识委托 |
委托提供了一种回调的函数机制,委托确保回调的方法是类型安全的,clr最重要的目标之一是类型安全。
非托管的c/c++中回调函数只是个内存地址。
blah blah blah......
什么委托基本语法啊,什么委托回调静态回调实例方法啊!啊!啊!
blah blah blah......
blah blah blah......
blah blah blah......
委托揭秘 |
定义一个委托clr所做的幕后工作
public delegate void Mydelegate(Int32 i);
编译器生成的代码
public class Mydelegate : System.MulticastDelete
{
public Mydelegate(Int32 i, IntPtr method);
public virtual string Invoke(Int32 i);
public virtual IAsyncResult BeginResult(Int32 i, AsyncCallback callback, Object object);
public virtual void EndInvoke(IAsyncResult result);
}
委托的继承关系
我们的委托继承--->System.MulticastDelete
System.MulticastDelete继承--->System.Delegate
System.Delegate继承--->System.object
委托放到什么地方?
有些人把委托放到和class同级的地方,也就是全局,有些人把委托放到class里面,到底怎么放才对?
Jeffrey说:"随便你娃怎么放!你可以把它嵌套到类型中!你也可以把他放到全局范围中定义!委托是类,能够定义类的地方都可以定义委托。"
委托的可访问性
1.把委托放到全局范围,和class同级
public delegate void Mydelegate(Int32 i);
class Program
{
static void Main(){}
}
这个时候il代码
所以种情况委托是公开的。
2.尝试下把委托定义为私有的
private delegate void Mydelegate(Int32 i);
class Program
{
static void Main(){}
}
尝试编译代码,但是编译器报错
错误1命名空间中定义的元素无法显式声明为 private、protected 或 protected internal
结果很悲剧!!!!
3.把委托放到类里面
class Program
{
public delegate void Mydelegate(Int32 i);
static void Main() { }
}
这个时候委托是公开的,可以在其他地方调用这个委托
public class a
{
public void test()
{
Program.Mydelegate my = test1;
my(2);
}
public void test1(Int32 i) { Console.WriteLine(i); }
}
4.特殊的情况
public class a
{
public delegate void Mydelegate(Int32 i);
public event Mydelegate Myevent;
}
当类中有个委托类型的事件,那么外部就不能直接使用委托了,这个时候就相当于委托是字段,而事件是属性。那么就体现了封装性了。
你可以试试在其它类中来访问这个委托,完全不给你机会!只能通过事件。
System.MulticastDelete |
由于所有委托类型都派生自System.MulticastDelete,逼不得已要研究它!!!
它有3个重要的非公共字段,我们定义的委托类型继承了这3个字段。
字段 |
类型 |
说明 |
_target |
System.Object |
委托对象包装一个静态方法的时候为null,实例方法的时候是回调方法要操作的对象,也就是实例方法的this值 |
_methodPtr |
System.IntPtr |
一个内部整数值,clr用它标识要回调的方法 |
_invocationLis |
System.Object |
一般是null,构造一个委托链时,它可以引用一个委托数组 |
说了字段现在说说2个主要的属性Target和Method
Target返回一个引用,它指向回调方法要操作的对象。
Method要回调方法的内存地址
还有就是委托类型的Invoke方法,就是它去调用那个要回调的方法。
委托对象 a,可以写a();也可以直接去a.Invoke();
我疯了才去用a.Invoke(),浪费键盘寿命
委托链 |
童鞋们!委托的+=,-=是不是用得很爽,其实最开始没得这个!让你回到解放前
public static Delegate Combine(Delegate a, Delegate b);
上面那个就是+=的祖宗老大爷!
public delegate void Mydelegate();
class Program
{
static void Main()
{
Mydelegate my1 = new Mydelegate(test1);
Mydelegate my2 = new Mydelegate(test2);
Mydelegate my3 = new Mydelegate(test3);
Mydelegate my = null;
my = (Mydelegate)Delegate.Combine(my, my1);
my = (Mydelegate)Delegate.Combine(my, my2);
my = (Mydelegate)Delegate.Combine(my, my3);
my();
Console.WriteLine("------丝袜般的分割线------");
my = (Mydelegate)Delegate.Remove(my, my1);
my = (Mydelegate)Delegate.Remove(my, new Mydelegate(test2));
my();
Console.Read();
}
public static void test1() { Console.WriteLine("1"); }
public static void test2() { Console.WriteLine("2"); }
public static void test3() { Console.WriteLine("3"); }
}
上面的代码就是委托链的解放前写法!爽吧!
伟大的微软为了解放我们这些苦命的程序员,就搞了+=和-=这2个操作符。
委托链不爽的地方!
如果委托链中一个方法异常或者堵塞很久,那么后面的方法都没法调用!所以默认的委托链调用算法不够健壮。
然后下面是Jeffrey的解决思路,擦 加了个try。我忍!
public delegate void Mydelegate();
class Program
{
static void Main()
{
a a1 = new a();
Mydelegate my1 = new Mydelegate(a1.test1);
Mydelegate my2 = new Mydelegate(a1.test2);
Mydelegate my3 = new Mydelegate(a1.test3);
Mydelegate my = null;
my = (Mydelegate)Delegate.Combine(my, my1);
my = (Mydelegate)Delegate.Combine(my, my2);
my = (Mydelegate)Delegate.Combine(my, my3);
Show(my);
Console.Read();
}
static void Show(Mydelegate my)
{
foreach (Mydelegate d in my.GetInvocationList())
{
try
{
d();
}
catch (InvalidOperationException e)
{
Console.WriteLine(e.Message);
Console.WriteLine(d.Target);
}
}
}
}
public class a
{
public void test1() { Console.WriteLine("1"); }
public void test2() { Console.WriteLine("2"); }
public void test3() { throw new InvalidOperationException("blah blah blah......"); }
}
委托与反射先欠着,我不是机器人
**************************** |
祖贤今天45岁了。