当前位置: 首页 > 编程日记 > 正文

说说.net事件和委托。

    一说到.net的事件,也许你会想都说教程满天飞,一个被说烂了的东西还有什么可以说的啊?是啊,的确有很多好文章剖析事件,比如张子阳先生的C# 中的委托和事件
重温Observer模式--热水器·改 这两篇文章让我弄懂了委托、事件和观察者模式的基础知识,另外深入的事件文章还有博客堂 破宝的事件三部曲,(btw 这些都是我看过的,如果你见见过更好的文章请跟帖以便更多人学习,谢谢。:))
   现在来说下这个被说烂了的东东我感觉需要注意的地方。
1 单播和多播事件
2 事件的显式定义(继而解释委托和事件的区别)
3 .net事件模型

  对于单播和多播事件概念。查资料是这么定义的:单播事件就是对象(类)发出的事件通知,只能被外界的某一个事件处理程序处理,而不能被多个事件处理程序处理,多播事件是对象(类)发出的事件通知,可以同时被外界不同的事件处理程序处理。

   说是这么简单,理解清楚不是很简单。有没有想过这里是到底怎么实现的呢?这里我读过《.net框架程序设计》第17.5 委托史话:System.Delegate与system.MulticastDelegate,如果有兴趣可以找来看看,system.MulticastDelegate定义于FCL继承自System.Delegate,这里MulticastDelegate其实就是多播委托,那么多播事件也是通过这个实现的,不用说Delegate大家都可以猜到是单播委托了,那么平时我们定义一个委托public delegate void Back(Object value, Int32 item, Int32 numItems)

当编译器遇到这句委托定义,会产生一个完整的类定义:

public class Back : System.MulticastDelegate
{
    public Back(Object target, Int32 methodPtr);

    public void virtual Invoke(Object value, Int32 item, Int32 numItems);
 
    public virtual IAsyncResult BeginInvoke(Object vlaue ,Int32. numItems, AsyncCallback callback,Object object);
 
  public virtual void EndInvoke(IAsyncResult result);
}
这个类其内部的方法看不懂没关系,先看这个类的Back是继承自System.MulticastDelegate,也就是说我们平时定义的委托几乎都是继承自多播委托的,那么为什么要有单播委托,这个具《.net框架程序设计》上说是微软.net框架设计的一个缺陷。所以这里大家记住平时定义的委托基本上都是多播的,也就是都可以用+=操作把委托组合成链,这里我不能不说破宝对多播和单播的理解有误。
  事件的显式定义,也许你还不知道显式定义是怎么回事,相信很多朋友平时自己定义事件也没注意过这个问题。

回忆下平时我们是怎么定义事件的呢?是不是下面的样子:

class MailManager
{

  
//定义一个委托类
  public delegate void MailMesgEventHandler(Object sender, EventArgs e);
  
 
//定义对应委托的事件
  public event MailMesgEventHandler MailMsg;
}
我们需要为事件先定义一个委托类(这里EventArgs我省略没自己定义特定子类),然后用这个委托类型定义事件。
看了很简单,是的,这里就是隐式定义事件,为什么叫隐式呢,我自己弄的名字哈哈,编译这句事件定义代码时要产更多的代码,就像下面这些简化的伪码:

private MailMesgEventHandler MailMesg = null;

 public void add_MailMesg(MailMesgEventHandler handler)
 {
  MailMesg = (MailMesgEventHandler);
  Delegate.Combine(MailMsg, handler);
 }

 public void remove_MailMesg(MailMesgEventHandler handler)
 {
  MailMesg = (MailMesgEventHandler);
  Delegate.Remove(MailMsg, handler);
 }
private MailMesgEventHandler MailMesg = null;

 
public void add_MailMesg(MailMesgEventHandler handler)
 {
  MailMesg 
= (MailMesgEventHandler);
  Delegate.Combine(MailMsg, handler);
 }

 
public void remove_MailMesg(MailMesgEventHandler handler)
 {
  MailMesg 
= (MailMesgEventHandler);
  Delegate.Remove(MailMsg, handler);
 }
可以看到这里编译器产生了三块东西,第一块是定义一个委托字段,下面是对这个字段的add和remove访问器,说到字段访问器,你也许会说属性!哈哈,是的,事件其实就是委托字段的访问器,和属性非常像,你可以这么理解,事件就是委托的属性,前面这句是从网上看到的,只不过属性用的是get和set,事件是add和remove
待会我们谈显式定义事件的时候,你会更确定事件就是委托的属性!
 看来是时候说显式定义事件啦,先看看下面的代码:

public delegate void MailMesgEventHandler(Object sender, EventArgs e);
private MailMesgEventHandler MailMesg;
public event MailMesgeventHandler MailMsg
{
 add
 {
  MailMesg = (MailMesgEventHandler);
  Delegate.Combine(MailMsg, handler);
 }
 
 remove
 {
  MailMesg = (MailMesgEventHandler);
  Delegate.Remove(MailMsg, handler);
 }
}
public delegate void MailMesgEventHandler(Object sender, EventArgs e);
private MailMesgEventHandler MailMesg;
public event MailMesgeventHandler MailMsg
{
 add
 {
  MailMesg 
= (MailMesgEventHandler);
  Delegate.Combine(MailMsg, handler);
 }
 
 remove
 {
  MailMesg 
= (MailMesgEventHandler);
  Delegate.Remove(MailMsg, handler);
 }
}
现在很像属性了吧,和隐式生成代码比较,这里不同的是add和remover的写法而已,那么显式定义的好处就很明显了
我们可以控制add/remove内部的逻辑,这样可以在+=(其实就是add,这里是操作符重载)和-=(其实就是remove)时更灵活。
  最后一个概念是.net事件模型,说事件模型之前先考虑一个问题,我们不管是隐式还是显式定义事件最后都要定义一个委托字段,大家知道System.Windows.Forms.Control类型中大约60个事件,如果Control类型在实现这些事件的时候让编译器自动产生委托字段以及add和remove访问器方法,那么每个Control类型将仅仅因为事件就有将近60个委托,
由于我们大多数时候在对象上登记的事件都很少,因此没创建一个Control类型(以及继承自Control的类型)的实例都会很浪费内存,顺便说下System.Web.UI.Control类型也存在这样的问题。
(以上斜体字是载自《.net框架程序设计修订版》238-239页)
那么我们怎么做能可以既定义事件又同时省去这些委托字段呢?

先看个图:



看完了图你是不是感觉如果用个表来存储委托key/值,如果添加委托,首先查询其中有没有相应的关键字,没有这时添加进去,有就合并到委托链。
这是个美妙的想法,同时可以各种委托有一个相同的“老窝”,而每个委托的工作又不相互干扰。
其实微软就给我们提供了这样的家,它就是System.ComponetModel.EventHandlerList
那么至于里面怎么实现的我是不知道,不过现在我们可以自己动手做个委托“老窝”。(注下面代码全部载自《.net框架程序设计修订版,》)

ContractedBlock.gifExpandedBlockStart.gifCode
  1using System;
  2using System.Collections.Generic;
  3using System.Text;
  4using System.Collections;
  5using System.Runtime.CompilerServices;
  6
  7namespace BaoBaoCore.Event
  8ExpandedBlockStart.gifContractedBlock.gif{
  9ExpandedSubBlockStart.gifContractedSubBlock.gif    /**//// <summary>
 10    /// 事件集合类
 11    /// 公用类似微软System.ComponentModel.EventHandlerList
 12    /// 速度比EventHandlerList快(因为其采用链表,而本类用的是hashtable)
 13    /// </summary>

 14    public class EventHandlerSet : IDisposable
 15ExpandedSubBlockStart.gifContractedSubBlock.gif    {
 16        //用于保存“事件键/委托值”对的私有散列表
 17        private Hashtable _events = new Hashtable();
 18
 19        //一个索引器,用于获取或设置与传入的事件对象的
 20        //散列键相关联的委托
 21        public virtual Delegate this[Object eventKey]
 22ExpandedSubBlockStart.gifContractedSubBlock.gif        {
 23            //如果对象不在集合中,则返回null
 24            get
 25ExpandedSubBlockStart.gifContractedSubBlock.gif            {
 26                return (Delegate)_events[eventKey];
 27            }

 28
 29            set
 30ExpandedSubBlockStart.gifContractedSubBlock.gif            {
 31                _events[eventKey] = value;
 32            }

 33        }

 34
 35        //在指定的事件对象的散列键对应的委托链表上添加/组合一个委托实例
 36        public virtual void AddHandler(Object eventKey, Delegate handler)
 37ExpandedSubBlockStart.gifContractedSubBlock.gif        {
 38            _events[eventKey] = Delegate.Combine((Delegate)_events[eventKey], handler);
 39        }

 40
 41        //在指定的事件对象的散列键对应的委托链表上移除一个委托实例
 42        public virtual void RemoveHandler(Object eventKey, Delegate handler)
 43ExpandedSubBlockStart.gifContractedSubBlock.gif        {
 44            _events[eventKey] = Delegate.Remove((Delegate)_events[eventKey], handler);
 45        }

 46
 47        //在指定的事件对象的散列键对应的委托链表上触发事件
 48        public virtual void Fire(Object eventKey, Object sender, EventArgs e)
 49ExpandedSubBlockStart.gifContractedSubBlock.gif        {
 50            Delegate d = (Delegate)_events[eventKey];
 51            if (d != null)
 52ExpandedSubBlockStart.gifContractedSubBlock.gif            {
 53ExpandedSubBlockStart.gifContractedSubBlock.gif                d.DynamicInvoke(new Object[] { sender, e });
 54            }

 55        }

 56
 57        //方法声明来源于IDisposable接口
 58        //释放对象以使散列表占用的内存资源在下一次垃圾
 59        //收集中被回收,从而阻止垃圾收集器提升其代价
 60        public void Dispose()
 61ExpandedSubBlockStart.gifContractedSubBlock.gif        {
 62            _events = null;
 63        }

 64
 65        //下面的静态方法返回一个对传入的EventHandlerSet
 66        //对象的线程安全的封装
 67        public static EventHandlerSet Synchronized(EventHandlerSet eventHandlerSet)
 68ExpandedSubBlockStart.gifContractedSubBlock.gif        {
 69            if (null == eventHandlerSet)
 70ExpandedSubBlockStart.gifContractedSubBlock.gif            {
 71                throw new ArgumentNullException("eventHandlerSet");
 72            }

 73            return new SynchronizedEventHandlerSet(eventHandlerSet);
 74        }

 75
 76        //下面的类在EventHandlerSet基础上提供了
 77        //一个线程安全的封装
 78        private class SynchronizedEventHandlerSet : EventHandlerSet
 79ExpandedSubBlockStart.gifContractedSubBlock.gif        {
 80            //引用非线程安全的对象
 81            private EventHandlerSet _eventHandlerSet;
 82
 83            //在非线程安全的对象上构造一个线程安全的封装
 84            public SynchronizedEventHandlerSet(EventHandlerSet eventHandlerSet)
 85ExpandedSubBlockStart.gifContractedSubBlock.gif            {
 86                this._eventHandlerSet = eventHandlerSet;
 87
 88                //释放基类中的散列表对象
 89                Dispose();
 90            }

 91
 92            //线程安全的索引器
 93            public override Delegate this[object eventKey]
 94ExpandedSubBlockStart.gifContractedSubBlock.gif            {
 95                [MethodImpl(MethodImplOptions.Synchronized)]
 96                get
 97ExpandedSubBlockStart.gifContractedSubBlock.gif                {
 98                    return _eventHandlerSet[eventKey];
 99                }

100
101                [MethodImpl(MethodImplOptions.Synchronized)]
102                set
103ExpandedSubBlockStart.gifContractedSubBlock.gif                {
104                    _eventHandlerSet[eventKey] = value;
105                }

106            }

107
108            //线程安全的AddHandler方法
109            [MethodImpl(MethodImplOptions.Synchronized)]
110            public override void AddHandler(object eventKey, Delegate handler)
111ExpandedSubBlockStart.gifContractedSubBlock.gif            {
112                _eventHandlerSet.AddHandler(eventKey, handler);
113            }

114
115            //线程安全的RemoveHandler方法
116            [MethodImpl(MethodImplOptions.Synchronized)]
117            public override void RemoveHandler(object eventKey, Delegate handler)
118ExpandedSubBlockStart.gifContractedSubBlock.gif            {
119                _eventHandlerSet.RemoveHandler(eventKey, handler);
120            }

121
122            //线程安全的Fire方法
123            [MethodImpl(MethodImplOptions.Synchronized)]
124            public override void Fire(object eventKey, object sender, EventArgs e)
125ExpandedSubBlockStart.gifContractedSubBlock.gif            {
126                _eventHandlerSet.Fire(eventKey, sender, e);
127            }

128        }

129    }
    
130}

131
以上是一个利用Hashtable存储委托的实现类,下面我自己写了个委托使用的具体案例,如下。
ContractedBlock.gifExpandedBlockStart.gifCode
  1using System;
  2using System.Collections.Generic;
  3using System.ComponentModel;
  4using System.Data;
  5using System.Drawing;
  6using System.Text;
  7using System.Windows.Forms;
  8
  9using BaoBaoCore.Event;
 10namespace WindowsSample
 11ExpandedBlockStart.gifContractedBlock.gif{
 12    public partial class Form1 : Form
 13ExpandedSubBlockStart.gifContractedSubBlock.gif    {
 14        //定义一个受保护的实例字段,改字段引用一个集合来管理一组事件/委托对。
 15        private EventHandlerSet _workEventSet = EventHandlerSet.Synchronized(new EventHandlerSet());
 16
 17        //构造一些只读且受保护的事件静态key
 18        protected static readonly Object WorkStartEventKey = new Object();
 19        protected static readonly Object WorkEndEventKey = new Object(); 
 20
 21        //为WorkStart事件定义继承自EventArgs的类型
 22        public class WorkStartEventArgs : EventArgs
 23ExpandedSubBlockStart.gifContractedSubBlock.gif        {
 24ContractedSubBlock.gifExpandedSubBlockStart.gif            字段#region 字段
 25            private DateTime _workStartTime;
 26            private string _message = "";
 27            #endregion

 28
 29ContractedSubBlock.gifExpandedSubBlockStart.gif            属性#region 属性
 30ExpandedSubBlockStart.gifContractedSubBlock.gif            /**//// <summary>
 31            /// 事件相关字串信息
 32            /// </summary>

 33            public string Message
 34ExpandedSubBlockStart.gifContractedSubBlock.gif            {
 35                get 
 36ExpandedSubBlockStart.gifContractedSubBlock.gif                {
 37                    return _message;
 38                }

 39            }

 40
 41ExpandedSubBlockStart.gifContractedSubBlock.gif            /**//// <summary>
 42            /// 启动时间
 43            /// </summary>

 44            public DateTime WorkStartTime
 45ExpandedSubBlockStart.gifContractedSubBlock.gif            {
 46                get
 47ExpandedSubBlockStart.gifContractedSubBlock.gif                {
 48                    return _workStartTime;
 49                }

 50            }

 51            #endregion

 52
 53ContractedSubBlock.gifExpandedSubBlockStart.gif            构造方法#region 构造方法
 54ExpandedSubBlockStart.gifContractedSubBlock.gif            /**//// <summary>
 55            /// 构造方法
 56            /// </summary>
 57            /// <param name="message">事件信息</param>
 58            /// <param name="workStartTime">启动时间</param> 

 59            public WorkStartEventArgs(string message, DateTime workStartTime)
 60ExpandedSubBlockStart.gifContractedSubBlock.gif            {
 61                _message = message;
 62                _workStartTime = workStartTime;
 63            }

 64            #endregion

 65        }

 66
 67        //为WorkEnd事件定义继承自EventArgs的类型
 68        public class WorkEndEventArgs : EventArgs
 69ExpandedSubBlockStart.gifContractedSubBlock.gif        {
 70ContractedSubBlock.gifExpandedSubBlockStart.gif            字段#region 字段
 71            private DateTime _workEndTime;
 72            private string _message = "";
 73            #endregion

 74
 75ContractedSubBlock.gifExpandedSubBlockStart.gif            属性#region 属性
 76ExpandedSubBlockStart.gifContractedSubBlock.gif            /**//// <summary>
 77            /// 事件相关字串信息
 78            /// </summary>

 79            public string Message
 80ExpandedSubBlockStart.gifContractedSubBlock.gif            {
 81                get
 82ExpandedSubBlockStart.gifContractedSubBlock.gif                {
 83                    return _message;
 84                }

 85            }

 86
 87ExpandedSubBlockStart.gifContractedSubBlock.gif            /**//// <summary>
 88            /// 启动时间
 89            /// </summary>

 90            public DateTime WorkEndTime
 91ExpandedSubBlockStart.gifContractedSubBlock.gif            {
 92                get
 93ExpandedSubBlockStart.gifContractedSubBlock.gif                {
 94                    return _workEndTime;
 95                }

 96            }

 97            #endregion

 98
 99ContractedSubBlock.gifExpandedSubBlockStart.gif            构造方法#region 构造方法
100ExpandedSubBlockStart.gifContractedSubBlock.gif            /**//// <summary>
101            /// 构造方法
102            /// </summary>
103            /// <param name="message">事件信息</param>
104            /// <param name="workStartTime">结束时间</param> 

105            public WorkEndEventArgs(string message, DateTime workEndTime)
106ExpandedSubBlockStart.gifContractedSubBlock.gif            {
107                _message = message;
108                _workEndTime = workEndTime;
109            }

110            #endregion

111        }

112
113        //为事件定义委托原型
114        public delegate void WorkStartEventHandler(Object sender, WorkStartEventArgs e);
115        public delegate void WorkEndEventHandler(Object sender, WorkEndEventArgs e);
116
117        //定义WorkStart访问器方法用于在集合上添加/移除委托实例
118        public event WorkStartEventHandler WorkStart
119ExpandedSubBlockStart.gifContractedSubBlock.gif        {
120            add
121ExpandedSubBlockStart.gifContractedSubBlock.gif            {
122                _workEventSet.AddHandler(WorkStartEventKey, value);
123            }

124
125            remove
126ExpandedSubBlockStart.gifContractedSubBlock.gif            {
127                _workEventSet.RemoveHandler(WorkStartEventKey, value);
128            }

129        }

130
131        //定义WorkEnd访问器方法用于在集合上添加/移除委托实例
132        public event WorkEndEventHandler WorkEnd
133ExpandedSubBlockStart.gifContractedSubBlock.gif        {
134            add
135ExpandedSubBlockStart.gifContractedSubBlock.gif            {
136                _workEventSet.AddHandler(WorkEndEventKey, value);
137            }

138
139            remove
140ExpandedSubBlockStart.gifContractedSubBlock.gif            {
141                _workEventSet.RemoveHandler(WorkEndEventKey, value);
142            }

143        }

144
145        //为唤醒OnWorkStart事件定义一个受保护的虚方法
146        protected virtual void OnWorkStart(WorkStartEventArgs e)
147ExpandedSubBlockStart.gifContractedSubBlock.gif        {
148            _workEventSet.Fire(WorkStartEventKey, this, e);
149        }

150
151        //为唤醒OnWorkEnd事件定义一个受保护的虚方法
152        protected virtual void OnWorkEnd(WorkEndEventArgs e)
153ExpandedSubBlockStart.gifContractedSubBlock.gif        {
154            _workEventSet.Fire(WorkEndEventKey, this, e);
155        }

156
157        public Form1()
158ExpandedSubBlockStart.gifContractedSubBlock.gif        {
159            InitializeComponent();
160
161            //绑定自定义事件,通过结果可以看出先响应先添加的响应委托
162            this.WorkStart += new WorkStartEventHandler(WorkStart1);
163            this.WorkStart += new WorkStartEventHandler(WorkStart2);
164
165            this.WorkEnd += new WorkEndEventHandler(WorkEnd2);
166            this.WorkEnd += new WorkEndEventHandler(WorkEnd1);
167        }

168
169        private void button1_Click(object sender, EventArgs e)
170ExpandedSubBlockStart.gifContractedSubBlock.gif        {
171             OnWorkStart(new WorkStartEventArgs("工作开始啦!!", DateTime.Now));
172        }

173
174        private void button2_Click(object sender, EventArgs e)
175ExpandedSubBlockStart.gifContractedSubBlock.gif        {
176            OnWorkEnd(new WorkEndEventArgs("工作结束啦!!", DateTime.Now));
177        }

178
179        //事件相关响应方法
180        private void WorkStart1(object sender, WorkStartEventArgs e)
181ExpandedSubBlockStart.gifContractedSubBlock.gif        {
182            MessageBox.Show(e.Message + "  被WorkStart1方法捕获到开始事件");
183        }

184
185        private void WorkStart2(object sender, WorkStartEventArgs e)
186ExpandedSubBlockStart.gifContractedSubBlock.gif        {
187            MessageBox.Show(e.WorkStartTime.ToString() + "  被WorkStart2方法捕获到开始事件");
188        }

189
190        private void WorkEnd1(object sender, WorkEndEventArgs e)
191ExpandedSubBlockStart.gifContractedSubBlock.gif        {
192            MessageBox.Show(e.Message + "  被WorkEnd1方法捕获到结束事件");
193        }

194
195        private void WorkEnd2(object sender, WorkEndEventArgs e)
196ExpandedSubBlockStart.gifContractedSubBlock.gif        {
197            MessageBox.Show(e.WorkEndTime.ToString() + "  被WorkEnd2方法捕获到结束事件");
198        }

199
200       
201    }

202}
需要说明的是,EventHandlerSet只有在多处使用时才能体现出来其优势,因为为每个事件定义关键字也需要内存,这里我定义成静态类的字段是有目的的,有兴趣可以想想原因。

好了到这里基本说完了,你看完了这篇事件的东东会不会再次说——都说破啦,哈哈。

代码下载

LoveBaoBao

作者:LoveBaoBao

出处:http://lovebaobao.cnblogs.com

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

转载于:https://www.cnblogs.com/LoveBaoBao/archive/2008/12/17/1356769.html

相关文章:

【cs229-Lecture2】Linear Regression with One Variable (Week 1)(含测试数据和源码)

从Ⅱ到Ⅳ都在讲的是线性回归&#xff0c;其中第Ⅱ章讲得是简单线性回归&#xff08;simple linear regression, SLR&#xff09;&#xff08;单变量&#xff09;&#xff0c;第Ⅲ章讲的是线代基础&#xff0c;第Ⅳ章讲的是多元回归&#xff08;大于一个自变量&#xff09;。 本…

101种设计模式

https://sourcemaking.com/design-patterns-and-tips

(C++)1032 挖掘机技术哪家强

笔记&#xff1a;考虑到输入只有一所学校&#xff0c;且得分还为0的特殊情况&#xff0c;应该把high初始化为1 #include<cstdio> #include<cmath> #include<cstring> #include<algorithm> using namespace std;int grds[100010] {0};int main(){int …

数据库打开报错: 值不能为空

报错信息如下&#xff1a; 数据库客户端打不开 解决方案&#xff1a; 找到下面的目录C:\Users\<username>\AppData\Local\Temp 创建一个空文件夹 名称是&#xff1a; 2 重新打开数据库转载于:https://www.cnblogs.com/Mander/p/3921251.html

学习 JavaScript (四)核心概念:操作符

JavaScript 的核心概念主要由语法、变量、数据类型、操作符、语句、函数组成&#xff0c;前面三个上一篇文章已经讲解完了。后面三个内容超级多&#xff0c;这篇文章主要讲解的是操作符。 操作符 什么叫做操作符&#xff1f; 这是一种工具&#xff0c;帮助我们操作字符串、数字…

(C++)1011 World Cup Betting

笔记&#xff1a;我觉得这一次的代码很优雅 #include<cstdio> #include<cmath> #include<cstring> #include<algorithm> using namespace std;int maxPro(double a[3]){//返回值最大的下标 int idx0,max_pro0;for(int i0;i<3;i){if(a[i]>max_pr…

Ext学习-前后交互模式介绍

在前后台交互模式的介绍中&#xff0c;实际上就是Store中Proxy相关的内容&#xff0c;比如Ajax提交。 所以详细的文档请参考&#xff1a; Ext学习-基础概念&#xff0c;核心思想介绍 中关于数据模型和MVC结构部分。 作者&#xff1a;sdjnzqr 出处&#xff1a;http://www.cnblog…

让你彻底明白什么叫游戏引擎(1)

在阅读各种游戏介绍的时候我们常常会碰见“引擎”&#xff08;Engine&#xff09;这个单词&#xff0c;引擎在游戏中究竟起着什么样的作用&#xff1f;它的进化对于游戏的发展产生了哪些影响&#xff1f;希望下面这篇文章能为大家释疑。以希望能够帮助一些刚进入游戏行业的小菜…

185.dubbo 后台管理系统

2019独角兽企业重金招聘Python工程师标准>>> 1. 效果及目的 效果&#xff1a; 目的&#xff1a;查看 管理服务 2. 启动要求 &#xff08;1&#xff09;项目是dubbo &#xff08;2&#xff09;jdk 1.7 (3) dubbo的war要与zookeeper在同一台服务上 3. 安装zookeeper 要…

(C++)1027 打印沙漏

笔记&#xff1a;星号右边的空格不用打印 #include<cstdio> #include<cmath> #include<cstring> #include<algorithm> using namespace std;int main(){int n;char c;scanf("%d %c",&n,&c);int clock[23];int col;for(int i1;i<…

黑帽大会2014:10个酷炫的黑客工具

http://www.csdn.net/article/2014-08-21/2821304 用于恶意软件分析的Maltrieve 安全研究人员使用Maltrieve工具收集服务器上的恶意软件。通过这个开源工具&#xff0c;恶意软件分析人员可以通过分析URL链表和已知的托管地址获得最新鲜的样本。 Kyle Maxwell是VeriSign的一名威…

C#无符号右移

/// <summary>/// 无符号右移&#xff0c;与JS中的>>>等价/// </summary>/// <param name"x">要移位的数</param>/// <param name"y">移位数</param>/// <returns></returns>public static int …

1027 Colors in Mars

笔记&#xff1a;本题属于进制转换&#xff0c;但是考察的重点不在除基取余上&#xff0c;因为转化得到的数只有两位&#xff0c;很容易得到每位上面应该是什么&#xff0c;但是和其他题不同的地方在于&#xff0c;每位可填的不见得是0~9&#xff0c;还包括ABC&#xff0c;这就…

json对象和json字符串转换方法

在WEB数据传输过程中&#xff0c;json是以文本&#xff0c;即字符串的轻量级形式传递的&#xff0c;而客户端一般用JS操作的是接收到的JSON对象&#xff0c;所以&#xff0c;JSON对象和JSON字符串之间的相互转换、JSON数据的解析是关键。 先明确2个概念例如&#xff1a; JSON字…

python-docx操作

import docx# 读取docx文档内容def readWord():doc docx.Document(demo.docx)fullText []for para in doc.paragraphs:fullText.append( para.text)print(\n . join(fullText))readWord()官方API&#xff1a;https://python-docx.readthedocs.io/en/latest/index.html ;转载…

javascript中FORM表单的submit()方法经验教训.

author songfeng 因为JS内对象的方法实际上是存储语句的一个类似于指针的东西. 其指向了内存的一个位置, 也就是其函数的位置,当然也可以让其指向一个变量值. var foo new Object();foo.bar function() {} //现在foo.bar就是指向了这个函数的内存位置.foo.bar &q…

1058 A+B in Hogwarts

笔记&#xff1a;和乙级的在霍格沃兹找零钱不同&#xff0c;这里不需要判断给出的两个数的大小&#xff0c;也没必要先都换算成最小的单位&#xff0c;可以直接从最低位开始加&#xff0c;如果超过该位的范围&#xff0c;则向上一位进一即可。 #include<cstdio> #includ…

DDD领域驱动设计之聚合、实体、值对象

关于具体需求&#xff0c;请看前面的博文&#xff1a;DDD领域驱动设计实践篇之如何提取模型&#xff0c;下面是具体的实体、聚合、值对象的代码&#xff0c;不想多说什么是实体、聚合等概念&#xff0c;相信理论的东西大家已经知晓了。本人对DDD表示好奇&#xff0c;没有在真正…

C#用 SendKyes 结合 Process 或 API FindWindow、SendMessage(PostMessage) 等控制外部程序

Win32 平台是 消息驱动模式.Net 框架是 事件驱动模式标题所指的 “控制外部程序”&#xff0c;外部程序是指与本程序无内在相关性的另外一个程序 基于上面提到的&#xff0c;对于.NET的winform程序&#xff0c;在默认情况下&#xff08;即未对接收消息的事件做自定义处理&#…

springMVC swagger2

参考地址&#xff1a;https://www.cnblogs.com/exmyth/p/7183753.html https://blog.csdn.net/programmer_sean/article/details/72236948 1. maven 依赖 <dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger2</artifactId&…

1061 Dating

笔记&#xff1a; 第一个输出根据的是大写字母 第二个输出根据的是0-9andA-N 第三个输出根据的是大写字母和小写字母 知道范围便方便确定边界 两两比对时&#xff0c;先遍历一个字符串&#xff0c;遇到在范围内的字符&#xff0c;看其和第二个字符串同位置的字符是否相等 …

PA 项目创建任务

---- 创建任务 DECLAREp_project_id NUMBER : 155233;p_task_number VARCHAR2(240) : CXYTEST0001;p_task_name VARCHAR2(240) : 接口测试CXYTEST0001;p_task_description VARCHAR2(240) : TASKCXYTEST0001;p_scheduled_start_date DAT…

SSM登陆拦截器实现

首先在springmvc中配置拦截器 <!-- 配置拦截器 --><mvc:interceptors><mvc:interceptor><!-- 拦截所有mvc控制器 --><mvc:mapping path"/**"/><!-- mvc:exclude-mapping是另外一种拦截&#xff0c;它可以在你后来的测试中对某个页面…

AGG 学习笔记

我了解的&#xff21;&#xff27;&#xff27;的总体结构按照文件大致分为&#xff1a;   &#xff11;&#xff09;基本定义&#xff08;config,basics....)&#xff1b;   &#xff12;&#xff09;基本操作、类型&#xff08;主要供&#xff21;&#xff27;&#xff2…

1073 Scientific Notation

笔记&#xff1a;这是我迄今为止写过的最复杂的字符串处理算法题。 收获&#xff1a;分而治之&#xff0c;想不清楚就自己设计测试用例和结果。列举然后归类。 以下是程序流程图 #include<cstdio> #include<cmath> #include<cstring> #include<algorith…

几个笔试题目总结

1、阿里某个笔试题&#xff0c;两个字符串text&#xff0c;query&#xff0c;找到text中包含的最长的query的字串&#xff1a; public static String subStr(String text, String query) {if (text ! null && query ! null) {int length query.length();for (int i 0…

baidu mp3竟然还加密,太扯了

baidu mp3竟然还加密&#xff0c;太扯了 public class BaiduHelper { static int F 0; static string I "", J ""; static string O ""; static string E ""; static int[] K new int[1000…

Ubuntu 之linux与windows互传文件

Windows系统下与linux传输文件 windows环境下&#xff0c;windows传出数据到linux下 确保ubuntu安装了ssh服务端。如果没有安装&#xff0c;使用以下命令安装&#xff1a; sudo aptget install ssh service sshd restart 2.windows下下载pscp.exe软件从PuTTY官方网站下载pscp.e…

1048 数字加密 --非满分

16/20 非满分&#xff0c;待来日复习双指针再分析原因 #include<cstdio> #include<cmath> #include<cstring> #include<algorithm> #include<bits/stdc.h> using namespace std;void reverStr(char str[]){int len strlen(str);for(int i0;i&l…

端到端对话模型新突破!Facebook发布大规模个性化对话数据库

作者&#xff5c;Pierre-Emmanuel Mazare 等译者&#xff5c;郝毅编辑&#xff5c;Debra出处丨 AI 前线AI 前线导读&#xff1a;聊天机器人是目前非常流行的一种人工智能系统。目前大部分聊天机器人的衔接性都不是很好&#xff0c;尤其是在没有主动的重调优策略下训练出的端到端…