导航
  • 主页
  • C#综合技术
  • C#互联网桌面应用
  • AppLauncher
  • WinForm
  • WPF
  • 问答

委托订阅取消不掉的问题?

newmankind 2013-10-18 10:53:41
string[] arr = GlobalStatic.marketChannel.dicMarketTransfer.Keys.ToArray();
foreach (string _InstrumentID in arr)
{
GlobalStatic.marketChannel.dicMarketTransfer[_InstrumentID].PushMarketInfoEvent -= dicMarketTransfer[_InstrumentID].ReciveMarketInfo;

}

GlobalStatic.marketChannel.dicMarketTransfer[_InstrumentID] 和 dicMarketTransfer[_InstrumentID]. 均继承了以下接口(已实现)
public interface IMarketTransfer
{
event PushMarketInfoEventHandler PushMarketInfoEvent;
void ReciveMarketInfo(DataRow drMarket);
}

按照官方文档,非匿名委托订阅 ,应该可以 用-=取消的啊,为什么取消不掉,求解,谢谢!
...全文
212 点赞 收藏 11
写回复
11 条回复
切换为时间正序
当前发帖距今超过3年,不再开放新的回复
发表回复
qldsrx 2013-10-23
引用 8 楼 u011303459 的回复:

//订阅
GlobalStatic.marketChannel.dicMarketTransfer[_instrumentID].PushMarketInfoEvent
                += new PushMarketInfoEventHandler(dicMarketTransfer[_instrumentID].ReciveMarketInfo);
//取消
GlobalStatic.marketChannel.dicMarketTransfer[_InstrumentID].PushMarketInfoEvent -= dicMarketTransfer[_InstrumentID].ReciveMarketInfo;
看看右边的项,订阅多了new,这样2个对象就不是同一个了。订阅改成下面的试试。 GlobalStatic.marketChannel.dicMarketTransfer[_instrumentID].PushMarketInfoEvent += dicMarketTransfer[_instrumentID].ReciveMarketInfo;
那样写没错,你自己对委托的概念不清楚,委托不是类,不能用类的思考方式去处理。
引用 9 楼 newmankind 的回复:
我疑惑就是 注册 和取消注册同时指向,同一个dictionary 的同一个实例的同一个函数,dicMarketTransfer[_InstrumentID].ReciveMarketInfo 应该这种写法表述不会有问题啊,为啥就取消不掉呢?
有几个疑点: 一、RegEvent()方法内部有注册事件,但没有看到取消,虽然注册的是空方法,不代表你实际方法也是空的。 二、pushMarketInfo可能为null,你却直接在ReciveMarketInfo内部使用,这是不安全的。 三、看定义,dicMarketTransfer似乎不是静态的,GlobalStatic.marketChannel.dicMarketTransfer似乎又是静态的,这两者似乎不是同一个对象,这里面是否存在变量偷换的情况。 四、GlobalStatic.marketChannel.dicMarketTransfer.Keys在注册和取消时,是否保证不曾发生过任何改变。
回复
newmankind 2013-10-23
我疑惑就是 注册 和取消注册同时指向,同一个dictionary 的同一个实例的同一个函数,dicMarketTransfer[_InstrumentID].ReciveMarketInfo 应该这种写法表述不会有问题啊,为啥就取消不掉呢?
回复
feiniao19830822 2013-10-23

//订阅
GlobalStatic.marketChannel.dicMarketTransfer[_instrumentID].PushMarketInfoEvent
                += new PushMarketInfoEventHandler(dicMarketTransfer[_instrumentID].ReciveMarketInfo);
//取消
GlobalStatic.marketChannel.dicMarketTransfer[_InstrumentID].PushMarketInfoEvent -= dicMarketTransfer[_InstrumentID].ReciveMarketInfo;
看看右边的项,订阅多了new,这样2个对象就不是同一个了。订阅改成下面的试试。 GlobalStatic.marketChannel.dicMarketTransfer[_instrumentID].PushMarketInfoEvent += dicMarketTransfer[_instrumentID].ReciveMarketInfo;
回复
newmankind 2013-10-23
顺序是,先初始化,填值,注册,(到此处这个流程正常的),取消注册,(这里取消不掉)。
回复
newmankind 2013-10-23
//本地 dicMarketTransfer 初始化 dicMarketTransfer = new Dictionary<string, IMarketTransfer>(); //本地 dicMarketTransfer 填值, if (!dicMarketTransfer.ContainsKey(InstrumentID)) { MarketTransfer mt = new MarketTransfer(InstrumentID); mt.Init(); dicMarketTransfer.Add(InstrumentID, mt); } //MarketTransfer 实现接口IMarketTransfer public class MarketTransfer:IMarketTransfer { //public ControlInfo controlInfo = null; public string InstrumentID = ""; public MarketTransfer(string InstrumentID_p) { InstrumentID = InstrumentID_p; //InitMarketUnit(InstrumentID); } public void Init() { RegEvent(); } public void RegEvent() { PushMarketInfoEvent += new PushMarketInfoEventHandler(PushMarketInfo); } public PushMarketInfoEventHandler pushMarketInfo = null; public event PushMarketInfoEventHandler PushMarketInfoEvent { add { pushMarketInfo += value; } remove { pushMarketInfo -= value; } } public void PushMarketInfo(DataRow drMarket) { } public void ReciveMarketInfo(DataRow drMarket) { try { Delegate [] DelegateGroup = pushMarketInfo.GetInvocationList(); //20130721在此处注入数据感觉不合适,应该作为传输的drmarket //如果下面挂着接收单位,则证明此时有效channel,否则可能是实虚切换后废channel //有效之后则处理markunit诸多变量,赶在异步发送之前 // if (DelegateGroup.Length > 0) //{ // GlobalStatic.marketPools.DicMarketUnits[InstrumentID].ReciveMarket(drMarket); //} foreach (PushMarketInfoEventHandler g in DelegateGroup) { g.BeginInvoke(drMarket,DelegMarketCallBack,g); } } catch (System.Exception ex) { GlobalStatic.logInfo.SaveExceptionLog(ex); } } public void DelegMarketCallBack(IAsyncResult asyncResult) { //到这儿委托已经在异步线程中执行完毕 PushMarketInfoEventHandler deleg = (PushMarketInfoEventHandler)asyncResult.AsyncState; //委托执行的异常会在EndInvoke时抛出来 try { //使用BeginInvoke时传入委托的EndInvoke获得计算结果,这时候计算结果已经出来了,有异常的话也在这儿抛出来 deleg.EndInvoke(asyncResult); } catch (OverflowException ofex) { GlobalStatic.logInfo.SaveExceptionLog(ofex); } } //private void InitMarketUnit(string InstrumentID) //{ // if (!GlobalStatic.marketPools.DicMarketUnits.ContainsKey(InstrumentID)) // { // GlobalStatic.marketPools.DicMarketUnits.Add(InstrumentID, new MarketUnit(InstrumentID)); // } //} }
回复
newmankind 2013-10-23
注册部分 string[] arr = GlobalStatic.marketChannel.dicMarketTransfer.Keys.ToArray(); foreach (string _InstrumentID in arr) { RealMarketHookMarketTransfer(_InstrumentID); } //引用函数 private static void HookMarketTransfer(string _instrumentID) { GlobalStatic.marketChannel.dicMarketTransfer[_instrumentID].PushMarketInfoEvent += new PushMarketInfoEventHandler(dicMarketTransfer[_instrumentID].ReciveMarketInfo); }
引用 4 楼 qldsrx 的回复:
注册和取消的是不同的函数,即使函数名相同,但出现了继承关系后,不同对象就会产生不同的函数委托,不可能一样。你把最关键的注册部分省略了,这也是你犯错的根本所在,以为那个地方没错,其实就是错在那里。
回复
newmankind 2013-10-23
非常感谢qldsrx及其余诸位帮助提醒,终于找到原因了, 自己的问题,有一个bug,跟进去才发现,太粗心了, 因为静态全局调,HookMarketTransfer 调用了两次,所以取消订阅一次,还有一次。 这个错误确实低级, 最后 删掉多余的调用,在MarketTransfer,然后设置了一个内部函数 算是仅一次注册的门禁: public void HookInside(PushMarketInfoEventHandler _PushMarketInfoEvent) { if (!pushMarketInfo.GetInvocationList().Contains(_PushMarketInfoEvent)) { pushMarketInfo += _PushMarketInfoEvent; } }
回复
qldsrx 2013-10-20
注册和取消的是不同的函数,即使函数名相同,但出现了继承关系后,不同对象就会产生不同的函数委托,不可能一样。你把最关键的注册部分省略了,这也是你犯错的根本所在,以为那个地方没错,其实就是错在那里。
回复
liubaoen 2013-10-19
实例化时委托时不能使用匿名,只要指定委托实例的名字,那么就可以使用-=来解除委托. 已经测试过N次,没有此bug;
回复
newmankind 2013-10-19
挂载肯定是挂上了,因为就-= 没有达到预期效果,原来的挂载还在起作用。
回复
tcmakebest 2013-10-18
注意顺序问题,必须先挂载再取消
回复
发动态
发帖子
C#
创建于2007-09-28

10.5w+

社区成员

.NET技术 C#
申请成为版主
社区公告

全世界最好的语言,没有之一.