2024年2月9日发(作者:)
const;readonly;static readonly
const
1、静态
2、编译时赋值
3、值类型与string
readonly
1、可访问器赋值
2、运行时赋值
3、所有类型
static readonly
1、静态
2、编译时赋值,静态无参构造函数赋值
3、 所有类型
posted @ 2010-02-23 13:36 Mayvar 阅读(10) | 评论(0) | 编辑
2010年1月14日
C#消息机制
C#消息机制
一、消息概述
Windows下应用程序的执行是通过消息驱动的。消息是整个应用程序的工作引擎,我们需要理解掌握我们使用的编程语言是如何封装消息的原理。
1 什么是消息(Message)
消息就是通知和命令。在.NET框架类库中的命名空间中微软采用面对对象的方式重新定义了Message。新的消息(Message)结构的公共部分属性基本与早期的一样,不过它是面对对象的。
公共属性:
HWnd 获取或设定消息的处理函数
Msg 获取或设定消息的ID号
Lparam 指定消息的LParam字段
Wparam 指定消息的WParam字段
Result 指定为响应消息处理函数而向OS系统返回的值
2 消息驱动的过程
所有的外部事件,如键盘输入、鼠标移动、按动鼠标都由OS系统转换成相应的消息发送到应用程序的消息队列。每个应用程序都有一段相应的程序代码来检索、分发这些消息到对应的窗体,然后由窗体的处理函数来处理。
二、C#中的消息的封装
C#对消息重新进行了面对对象的封装,在C#中消息被封装成了事件。
ation类具有用于启动和停止应用程序和线程以及处理Windows消息的方法。
调用Run以启动当前线程上的应用程序消息循环,并可以选择使其窗体可见。
调用Exit或ExitThread来停止消息循环。
C#中用Application类来处理消息的接收和发送的。消息的循环是由它负责的。
从本质上来讲,每个窗体一般都对应一个窗体过程处理函数。那么,C#的一个Form实例(相当于一个窗体)收到消息后是如何处理消息的?其实,这个问题的分析也就是展示了C#的消息封装原理。
实现鼠标左键按下的消息的响应(WM_LBUTTONDOWN)
own += new
ventHandler(1_MouseDown1);
own += new
ventHandler(1_MouseDown2);
private void Form1_MouseDown1(object sender,
ventArgs e)
{
if(==)
("消息被Form1_MouseDown1函数响应");
}
private void Form1_MouseDown2(object sender,
ventArgs e)
{
if(==)
("消息被Form1_MouseDown2函数响应");
}
上面own是C#中的一个事件。它的定义如下:
public event MouseEventHandler MouseDown;
而MouseEventHandler的定义为:
public delegate void MouseEventHandler( object sender,MouseEventArgs e);
实际上,上面定义了一个委托类型MouseEventHandler。委托了启用了其它编程语言中的函数指针的解决方案。与C++的函数指针不同,委托是完全面向对象的,同时封装了对象实例和方法。本质上,委托把一个实例和该实例上的方法函数封装成一个可调用的实体,它是面对对象的、安全的。
我们可以把
own += new
ventHandler(1_MouseDown1);
这条语句看成向own添加一个函数指针。
事件是对象发送的消息,以发送信号通知操作的发生。引发(触发)事件的对象叫做事件发送方。捕获事件并对事件作出响应的对象叫做事件接收方。在事件通讯中,事件发送方类并不知道哪个对象或方法将接收到(处理)它引发的事件。所需要的是在发送方和接收方之间存在一个媒介(类似指针的机制)。.NET框架定义了一个特殊的类型(Delegate委托),该类型提供函数指针的功能。这样,委托就等效于一个类型安全的函数指针或一个回调函数。
前面我们向own事件添加了两个委托。
own += new
ventHandler(1_MouseDown1);
own += new
ventHandler(1_MouseDown2);
结果,我们的两个函数Form1_MouseDown1、Form1_MouseDown2在我们单击鼠标左键的时候都会被调用,而且调用的顺序和我们添加委托的顺序一致。
WM_LBUTTONDOWN消息首先被Application类从应用程序消息队列中取出,然后分发到相应的窗体。窗体使用MouseDown事件中的函数指针调用已经添加的响应函数。所以C#中的事件字段实质上是一个函数指针列表,用来维护一些消息到达时的响应函数的地址。
三、结论
C#中消息的工作流程:
C#中的消息被Application类从应用程序消息队列中取出,然后分发到消息对应的窗体,窗体对象的第一个响应函数是对象中的protected override void WndProc(ref
e e)方法。
它再根据消息的类型调用默认的消息响应函数(如OnMouseDown),默认的响应函数然后根据对象的事件字段(如own )中的函数指针列表,调用用户所加入的响应函数(如Form1_MouseDown1和Form1_MouseDown2),而且调用顺序和用户添加顺序一致。
四、再回首Application类
Application类有一个AddMessageFilter的静态方法,通过它我们可以添加消息筛选器,以便在向目标传递Windows消息时,检视这些消息。
使用消息筛选器来防止引发特定事件,或在将某事件传递给事件处理程序之前使用消息筛选器对其执行特殊操作。我们必须提供IMessageFilter接口的一个实现,然后才可以使用消息筛选器。以下的示范代码将演示在消息发往窗体前我们如何拦截它。我们拦截的同样是WM_LBUTTONDOWN消息。
using System;
using g;
using tions;
using entModel;
using ;
using ;
namespace MessageMech3
{
//实现消息过滤器接口
public class CLButtonDownFilter : IMessageFilter
{
public bool PreFilterMessage(ref Message m)
{
if (==0x0201)// WM_LBUTTONDOWN
{
("App中鼠标左键按下");
//返回值为true, 表示消息已被处理,不要再往后传递,因此消息被截获
//返回值为false,表示消息未被处理,需要再往后传递,因此消息未被截获
return true;
}
return false;
}
}
///
/// Summary description for WinForm.
///
public class WinForm :
{
///
/// Required designer variable.
///
private label1;
private ner components = null;
public WinForm()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();
//
// TODO: Add any constructor code after InitializeComponent call
//
//安装自己的过滤器
CLButtonDownFilter MyFilter=new CLButtonDownFilter();
sageFilter(MyFilter);
}
///
/// Clean up any resources being used.
///
protected override void Dispose (bool disposing)
{
if (disposing)
{
if (components != null)
{
e();
}
}
e(disposing);
}
#region Windows Form Designer generated code
///
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
///
private void InitializeComponent()
{
1 = new ();
dLayout();
//
// label1
//
lor = arent;
= ;
lor = olet;
= "label1";
= new (440, 32);
ex = 0;
= "演示如何在App对象中处理消息,请点鼠标左键";
ign = Center;
//
// Form1
//
aleBaseSize = new (7, 22);
lor = moke;
Size = new (440, 273);
ge(new l[] {1});
= new ("华文行楷", 15F,
r,
(()(134)));
= "WinForm";
= "WinForm";
,
//消息响应函数的调用顺序和添加委托的顺序一致
//即:以下命令将先调用Form1_MouseDown1再调用Form1_MouseDown2
//通过委托添加自己的鼠标按键消息响应函数1
own += new
ventHandler(1_MouseDown1);
//通过委托添加自己的鼠标按键消息响应函数2
own += new
ventHandler(1_MouseDown2);
Layout(false);
}
#endregion
///
/// 应用程序的主入口点。
///
[STAThread]
static void Main()
{
(new WinForm()); //启动当前Form线程上的应用程序消息循环
}
//要点1
// 通过C#提供的事件接口添加自己的鼠标按键事件的响应函数
//
private void Form1_MouseDown1(object sender,
ventArgs e)
{
if(==)
("消息被Form1_MouseDown1函数响应");
}
private void Form1_MouseDown2(object sender,
ventArgs e)
{
if(==)
("消息被Form1_MouseDown2函数响应");
}
//要点2
//通过覆盖基类的事件引发函数拦截消息
//
protected override void OnMouseDown( MouseEventArgs e)
{
if(==)
("消息被OnMouseDown函数响应");
//如果需要截获消息,可将eDown(e);语句注释掉
eDown(e);
}
//要点3
//通过覆盖基类的窗体函数拦截消息
//
protected override void WndProc(ref e e)
{
//如果需要截获消息,
//if(==0x0201)// WM_LBUTTONDOWN
// ("消息被WndProc函数响应");
//else
// c(ref e);
//不需要截获消息则为
if(==0x0201)// WM_LBUTTONDOWN
("消息被WndProc函数响应");
c(ref e);
}
}
}
以上代码我们首先用类CLButtonDownFilter实现了IMessageFilter接口,在WinForm初始化的时候我们安装了消息筛选器。程序实际执行的时候,在点击鼠标左键的时候,程序仅仅会弹出一个"App中鼠标左键按下"的消息框。因为我们在消息发往窗体前拦截了它,所以窗体将接收不到WM_LBUTTONDOWN消息。
如果我们把
if (==0x0201)// WM_LBUTTONDOWN
{
("App中鼠标左键按下");
return true;
}
改成
if (==0x0201)// WM_LBUTTONDOWN
{
("App中鼠标左键按下");
return false;
}
那么,我们在Application类处理消息后,消息将继续发往窗体。窗体的函数将可以处理此消息。程序执行效果是顺序弹出5个消息框。
1:<
2:<<消息被WndProc函数响应>>
3:<<消息被OnMouseDown函数响应>>
4:<<消息被Form1_MouseDown1函数响应>>
5:<<消息被Form1_MouseDown2函数响应>>
其实本文中已经说的挺详细的.弹出的对话框只是为了让你更直观的看出导致的结果.
先定义没过滤时的效果.
own +=
ventHandler(1_MouseDown1);
private void Form1_MouseDown1(object
ventArgs e)
{
if ( == )
("消息被Form1_MouseDown1函数响应");
}
主要有两种方法过滤实现过滤
第一种:
protected override void WndProc(ref Message m)
{
if ( == 0x0201)
return;
else
c(ref m);
}
第二种
new
sender,
不重写WndProc
//实现消息过滤器接口
public class CLButtonDownFilter : IMessageFilter
{
public bool PreFilterMessage(ref Message m)
{
if ( == 0x0201)// WM_LBUTTONDOWN
{
//返回值为true, 表示消息已被处理,不要再往后传递,因此消息被截获
//返回值为false,表示消息未被处理,需要再往后传递,因此消息未被截获
return true;
}
return false;
}
}
CLButtonDownFilter MyFilter = new CLButtonDownFilter();
sageFilter(MyFilter);
posted @ 2010-01-14 10:14 Mayvar 阅读(60) | 评论(0) | 编辑
2009年12月10日
C#算法(三)
希尔排序(Shell Sort)是插入排序的一种。因D.L.Shell于1959年提出而得名。
希尔排序基本思想
基本思想:
先取一个小于n的整数d1作为第一个增量,把文件的全部记录分成d1个组。所有距离为dl的倍数的记录放在同一个组中。先在各组内进行直接插入排序;然后,取第二个增量d2 该方法实质上是一种分组插入方法。 给定实例的shell排序的排序过程 假设待排序文件有10个记录,其关键字分别是: 49,38,65,97,76,13,27,49,55,04。 增量序列的取值依次为: 5,3,1 Shell排序的算法实现 1. 不设监视哨的算法描述 void ShellPass(SeqList R,int d) {//希尔排序中的一趟排序,d为当前增量 for(i=d+1;i<=n;i++) //将R[d+1..n]分别插入各组当前的有序区 if(R[ i ].key R[0]=R;j=i-d; //R[0]只是暂存单元,不是哨兵 do {//查找R的插入位置 R[j+d]=R[j]; //后移记录 j=j-d; //查找前一记录 }while(j>0&&R[0].key R[j+d]=R[0]; //插入R到正确的位置上 } //endif } //ShellPass void ShellSort(SeqList R) { int increment=n; //增量初值,不妨设n>0 do { increment=increment/3+1; //求下一增量 ShellPass(R,increment); //一趟增量为increment的Shell插入排序 }while(increment>1) } //ShellSort 注意: 当增量d=1时,ShellPass和InsertSort基本一致,只是由于没有哨兵而在内循环中增加了一个循环判定条件"j>0",以防下标越界。 2.设监视哨的shell排序算法 具体算法【参考书目[12] 】 算法分析 1.增量序列的选择 Shell排序的执行时间依赖于增量序列。 好的增量序列的共同特征: ① 最后一个增量必须为1; ② 应该尽量避免序列中的值(尤其是相邻的值)互为倍数的情况。 有人通过大量的实验,给出了目前较好的结果:当n较大时,比较和移动的次数约在nl.25到1.6n1.25之间。 2.Shell排序的时间性能优于直接插入排序 希尔排序的时间性能优于直接插入排序的原因: ①当文件初态基本有序时直接插入排序所需的比较和移动次数均较少。 ②当n值较小时,n和n2的差别也较小,即直接插入排序的最好时间复杂度O(n)和最坏时间复杂度0(n2)差别不大。 ③在希尔排序开始时增量较大,分组较多,每组的记录数目少,故各组内直接插入较快,后来增量di逐渐缩小,分组数逐渐减少,而各组的记录数目逐渐增多,但由于已经按di-1作为距离排过序,使文件较接近于有序状态,所以新的一趟排序过程也较快。 因此,希尔排序在效率上较直接插人排序有较大的改进。 希尔排序(C#)【vs2008 通過】 public void shellSort( int[] a) { int inner, temp; int h =3; while (h > 0) { for (int outer = h; outer <= - 1; outer++) { temp = a[outer]; inner = outer; while ((inner > h - 1) && a[inner - h] > temp) { a[inner] = a[inner - h]; inner -= h; } a[inner] = temp; } h = (h - 1) %3; } } posted @ 2009-12-10 09:02 Mayvar 阅读(61) | 评论(0) | 编辑 2009年12月9日 C#與二叉樹 首先,我們定義一個節點類: 代码 1 public class Node 2 { 3 public int Data; 4 public Node Left; 5 public Node Right; 6 public void DisplayNode() 7 { 8 (Data + " "); 9 } 10 } 再定義二叉樹: 包括二叉樹節點的插入和刪除 代码 1 /// 2 /// 二叉查找樹類 3 /// 4 public class BinarySearchTree 5 { 6 public Node root; 7 public BinarySearchTree() 8 { 9 root = null; 10 } 11 12 /// 13 /// 插入節點方法 14 /// 15 /// 節點鍵值 16 public void insert(int i) 17 { 18 Node newNode = new Node(); 19 = i; 20 21 if (root == null) 22 { 23 root = newNode; 24 } 25 else 26 { 27 Node current = root; 28 Node parent; 29 30 while (true) 31 { 32 parent = current; 33 34 if (i < ) 35 { 36 current = ; 37 if (current == null) 38 { 39 = newNode; 40 break; 41 } 42 } 43 else 44 { 45 current = ; 46 if (current == null) 47 { 48 = newNode; 49 break; 50 } 51 } 52 } 53 } 54 } 55 56 57 58 /// 59 /// 刪除二叉樹節點 60 /// 61 /// 所要刪除的節點 62 public bool delete(int key) 63 { 64 Node current = root; 65 Node parent = root; 66 bool isLeftChild = true; 67 68 while ( != key) 69 { 70 parent = current; 71 if (key < ) 72 { 73 isLeftChild = true; 74 current = ; 75 76 } 77 else 78 { 79 isLeftChild = false; 80 current = ; 81 } 82 if (current == null) 83 return false; 84 } 85 if (( == null) && ( == null)) 86 { 87 if (current == root) 88 root = null; 89 90 else if (isLeftChild) 91 92 = null; 93 } 94 else if ( == null) 95 { 96 if (current == root) 97 root = ; 98 else if (isLeftChild) 99 = ; 100 else 101 = ; 102 103 } 104 else if ( == null) 105 { 106 if (current == root) 107 root = ; 108 else if (isLeftChild) 109 = ; 110 else 111 = ; 112 } 113 114 else 115 { 116 Node successor = GetSuccessor(current); 117 if (current == root) 118 root = successor; 119 else if (isLeftChild) 120 = successor; 121 else 122 = successor; 123 = ; 124 } 125 return true; 126 } 127 128 /// 129 /// 找某節點的后繼節點 130 /// 131 /// 某節點 132 /// 133 public Node GetSuccessor(Node delNode) 134 { 135 Node successorParent = delNode; 136 Node successor = delNode; 137 Node current = ; 138 while (!(current == null)) 139 { 140 if ( != null) 141 successorParent = current; 142 143 successor = current; 144 current = ; 145 } 146 if (!(successor == )) 147 { 148 = ; 149 = ; 150 } 151 return successor; 152 } 153 } posted @ 2009-12-09 09:14 Mayvar 阅读(13) | 评论(0) | 编辑 2009年12月8日 C#算法(二) 基本的二叉查找 第一種採用遞歸的方式; 第二種是迭代方式; 直接看代碼: (VS2008中通過) 代码 1 public int RbinSearch(int value, int low, int upper,int[] a) 2 { 3 if (low > upper) return -1; 4 else 5 { 6 int mid = (low + upper) / 2; 7 if (value < a[mid]) 8 return RbinSearch(value, low, mid--,a); 9 else if (value == a[mid]) 10 return mid; 11 else 12 return RbinSearch(value, mid++, upper,a); 13 14 } 15 } 16 public int RbinSearch2(int value,int[] a) 17 { 18 int mid, low, upper; 19 low = 0; 20 upper = - 1; 21 while (low < upper) 22 { 23 mid =(low+upper)/2; 24 if (value == a[mid]) return mid; 25 else if (value > a[mid]) 26 { 27 low = mid + 1; 28 continue; 29 } 30 else 31 { 32 upper=mid -1; 33 continue; 34 } 35 } 36 return -1; 37 } posted @ 2009-12-08 11:18 Mayvar 阅读(19) | 评论(0) | 编辑 2009年12月7日 C#算法(一) 摘要: 一、冒泡排序(Bubble) 代码Code highlighting produced by Actipro CodeHighlighter (freeware)/-->1publicclassBubbleSorter2{3publicvoidSort(int[]list)4{5inti,j,temp;6booldone= 阅读全文 posted @ 2009-12-07 19:34 Mayvar 阅读(16) | 评论(0) | 编辑 C# API 摘要: C# APIC:ProgramFilesMicrosoftVisual Studio .NET FrameworkSDKSamples Technologies InteropPlatformInvoke WinAPIsCS目录下有大量的调用API的例子。一、调用格式using pServices; //引用此名称空间,简化后面的代码//... 阅读全文 posted @ 2009-12-07 14:18 Mayvar 阅读(20) | 评论(0) | 编辑 2009年12月5日 .NET Remoting 经典远程回调模型(三) 摘要: 今天来说下最后一项技术,用接口来代替定制委托。 前面讲过,定制委托时客户端传递一个实现好了的委托给服务端,同样的道理,客户端也可传递一个实现好了接口给服务端。看一下如何实现://定义回调接口public interface IClientCallback{//为了防止服务端因为阻塞而不能及时返回结果而影响//本地执行其他任务,因此加上ONEWAY属性。[OneWay] 阅读全文 posted @ 2009-12-05 17:21 Mayvar 阅读(64) | 评论(0) | 编辑 2009年12月4日 .NET Remoting 经典远程回调模型(二) 摘要: 为了简化客户端代码,可以将远程对象实现为异步操作的形式。 那么,当异步操作完成时如何通知客户端呢?? 这里,来说下第二种,使用定制委托实现回调。接着上个SimpleMath类说,public class SimpleMath:MarshalByRefObject{ private delegate int opDelegate(int n1, int n2); public 阅读全文 posted @ 2009-12-04 20:55 Mayvar 阅读(46) | 评论(0) | 编辑 2009年12月3日 .NET Remoting 经典远程回调模型(一) 摘要: 多层分布式应用开发是老生常谈的话题,其大大小小的框架也不计其数。 记得以前第一次开发分布式应用程序时候,还是用COM,那家伙,难的咧。。。!!还是借助delphi,光说配置成功都花了我好几个星期(实话),到处找资料,请教高手....结果算是实现了多台机器的分布式应用了,但很不灵活,每重配置一次,难受一次!! 在.NET Remoting, WCF 大行其道的今天,一切问题迎刃而解! 这里就说说我在... 阅读全文 posted @ 2009-12-03 22


发布评论