| 歲月輕品's profile蚂蚁的窝PhotosBlogLists | Help |
|
August 18 最近挺烦的我想要的生活是什么样的呢??
平淡,安静,
看看书,钓钓鱼
无聊了就出去走一走
呵呵呵,如此简单的而已
可惜,连这都很难做到
这个狗日的社会
慢慢把人都逼疯了
一个疯狂的社会,娘的 June 26 Smart Client Software Factory的启动过程应网友要求,结合参考实现(BankBranchWorkbench)写一篇关于 SCSF 内部工作原理的文章,需要读者有 SCSF 基础。基本概念和基本理念后面相关文章介绍。 SCSF 自动为我们建立了 Shell 项目。该项目的 ShellApplication 是SCSF 应用的入口程序,该类继承自 SmartClientApplication<TWorkItem, TShell> ,TWorkItem 是要指定的 root workitem ,TShell 是主窗体。
该类的 Main 方法通过 new ShellApplication().Run(); 启动应用。Run() 在父类 CabApplication 中实现,定义了 SCSF 的启动流程:1 public void Run() 其中核心流程有: 1. 首先创建 Builder builder = CreateBuilder(); CreaterBuilder()方法注册了 RootWorkItemInitializationStrategy ,EventBrokerStrategy,CommandStrategy,ObjectBuiltNotificationStrategy 总共四个策略,同时还添加了三个 Policy :SingletonPolicy,BuilderTraceSourcePolicy,ObjectBuiltNotificationPolicy 。 CreaterBuilder() 一般使用 builder.Strategies.AddNew 方法利用 ObjectBuilder 构建策略对象 (例如:builder.Strategies.AddNew<EventBrokerStrategy>(BuilderStage.Initialization))。 2. 子类可以通过重写 protected virtual void AddBuilderStrategies(Builder builder) 来给 ObjectBuilder 添加其他构建策略(在构建对象或者销毁对象时执行的操作)。 3. 初始化 RootWorkItem 这些准备工作做完后,第一件事是创建 RootWorkItem 。RootWorkItem 是通过 CreateRootWorkItem(builder) 完成的,以前面创建的 builder 作为参数:protected internal void InitializeRootWorkItem(Builder builder)。 InitializeRootWorkItem 中首先初始化 RootWorkItem 相关的 Builder 和 Locator (这两个都是 ObjectBuilder 的组件,用与对象创建和依赖注入): this.builder = builder; 其次对 rootWorkItem 进行初始化,主要执行以下三个方法: InitializeFields():设置或初始化 ObjectBuilder 相关的对象: Builder,Locator,ObjectBuiltNotificationPolicy,还有 workItem 的状态。 InitializeState():通过 Guid 生成本 workItem 实例的 ID (ID = Guid.NewGuid().ToString();); InitializeCollectionFacades():初始化管理 SCSF 核心组件的对象管理集合: ServiceCollection,commandCollection,workItemCollection,workspaceCollection,itemsCollection,smartPartCollection,eventTopicCollection,uiExtensionSiteCollection 。 RootWorkItem 构建完成后有一个可选的过程是创建 IVisualizer (用于在运行时查看 WorkItem 的状态):1 IVisualizer visualizer = CreateVisualizer(); 4. 添加服务: AddRequiredServices() 方法添加的服务有:TraceSourceCatalogService,WorkItemExtensionService,WorkItemTypeCatalogService,SimpleWorkItemActivationService,WindowsPrincipalAuthenticationService,ModuleLoaderService,FileCatalogModuleEnumerator,DataProtectionCryptographyService,CommandAdapterMapService,UIElementAdapterFactoryCatalog 。 AddConfiguredServices() 添加在配置文件中配置的服务,也就是运行我们通过配置的方式决定在 SCSF 框架启动时加载额外服务(Services)。 AddServices() 在 CabApplication 中是一个空的虚拟方法,允许我们创建 CabApplication 的子类来重写该方法以添加需要的 Services 。 5. 验证用户 通过获取在启动过程中注册的 IAuthenticationService 服务来进行用户验证(ObjectBuilder 的具体应用): 1 private void AuthenticateUser() 6. 处理 Shell 程序集(可执行的 Shell Assembly) 1 private void ProcessShellAssembly() 通过 ObjectBuilder 获取已注册的 IModuleLoaderService (默认的是 Microsoft.Practices.CompositeUI.Services.ModuleLoaderService),调用 ModuleLoaderService 的 Load 方法来通过SCSF Attribute(反射和特性)结合 ObjectBuilder 来加载 SCSF 核心组件,包括 Services、 Command 、 SmartParts、UIElement、workspace、Event Broker、State 等,这些属性(Attribute)主要有:ServiceAttribute,ServiceDependencyAttribute,SmartPartAttribute,CommandHandlerAttribute,EventPublicationAttribute,EventSubscriptionAttribute,ModuleDependencyAttribute,StateChangedAttribute,RootWorkItemExtensionAttribute,OptionalDependencyAttribute,TraceSourceAttribute,ComponentDependencyAttribute,WorkItemExtensionAttribute ,以后有时间会专门介绍这些属性的使用。 7. 构建 RootWorkItem (rootWorkItem.BuildUp()) RootWorkItem 通过 builder.BuildUp(locator, type, temporaryID, this, policies) 方法使用 ObjectBuilder 进行构建,前面介绍过 CabApplication 在 CreaterBuilder() 中注册了构建策略 RootWorkItemInitializationStrategy: builder.Strategies.Add(new RootWorkItemInitializationStrategy(this.OnRootWorkItemInitialized), BuilderStage.Initialization),该语句表明在创建 RootWorkItem 时 ObjectBuilder 会执行该策略并调用本类(CabApplication 或者重载的子类)的 OnRootWorkItemInitialized 方法:protected virtual void OnRootWorkItemInitialized()。CabShellApplication (CabApplication 的子类) 重写了该方法: 1 protected sealed override void OnRootWorkItemInitialized() 其中 RootWorkItem.Items.AddNew<TShell>() 语句创建了新的 TShell 主窗体对象(通过 ObjectBuilder 构建)并加入到 RootWorkItem 的 Items 集合中。 8. 通过配置加载模块(LoadModules()) RootWorkItem 构建完成后,SCSF 会根据 IModuleEnumerator 服务来枚举可以加载的模块(确定需要加载哪些模块),SCSF 中提供了两个 IModuleEnumerator 服务:FileCatalogModuleEnumerator(在配置文件中指明要加载哪些模块,默认的配置文件是 ProfileCatalog.xml )和 ReflectionModuleEnumerator(利用反射和 ModuleAttribute 来确定需要加载哪些模块)。同时 SCSF 的Package Guidance 为我们提供了一个 XmlStreamDependentModuleEnumerator ,用于从 Xml Stream 中确定需要加载哪些模块,这个可以用在通过 Web Service 将服务器上的配置发送到客户端的情况。 典型的配置文件示例 ProfileCatalog.xml :<SolutionProfile xmlns="http://schemas.microsoft.com/pag/cab-profile/2.0%22>
9. 完成对 RootWorkItem 的创建(rootWorkItem.FinishInitialization()) 同时 WorkItem 的 public void InitializeWorkItem() 是一个注入方法,有[InjectionMethod]属性标记,该方法执行时除了执行上面 rootworkItem中的初始化过程外,还会调用 InitializeServices 方法,该方法在 CabApplication 中是空方法,CabApplication 子类可以重写 protected virtual void InitializeServices() 方法,用于在 WorkItem 初始化时加载其他需要的服务。 10. 执行 rootWorkItem 的 run 方法 rootWorkItem.Run(); WorkItem 的 Run 方法直接调用 protected virtual void OnRunStarted() 方法:1 public void Run() OnRunStarted 方法触发 RunStarted 事件(public event EventHandler RunStarted) 1 protected virtual void OnRunStarted() 因此我们可以通过注册 RunStarted 事件或者在 WorkItem 子类中重写 OnRunStarted() 虚方法以便在 SCSF 启动过程中执行自己的操作,这是 SCSF 的又一扩展点。 11. 启动应用 Start() CabApplication 中的 Start 是一个抽象方法:protected abstract void Start(); 子类 FormShellApplication(public abstract class FormShellApplication<TWorkItem, TShell> : WindowsFormsApplication<TWorkItem, TShell>) 重写了Start : 1 protected override void Start() June 25 VSTS作Unit Test的总结Visual Studio 2005 集成了单元测试框架(Team Test),正好公司规范开发流程,需要提交Unit Test Log,以前都是用Nunit作单元测试,现在既然VS有了自己的UT类,就打算尝试一下,感觉和Nunit用起来差不多,没怎么深入,只是简单总结一下。 在弹出的“创建单元测试”对话框中的“输出项目”下拉框中选择“创建新的Visual C# 测试项目”,单击“确定”按钮,并在“新建测试项目”对话框中输入测试项目的名称(如:MySchoolTest),单击“创建”按钮后,就看见在原有的解决方案中生成了一个新的项目“MySchoolTest”。 AuthoringTest.txt 提供创建测试的说明,包括向项目增加其他测试的说明; 单元测试中,几个变量的简单介绍: Assert.AreEqual() 测试指定的值是否相等,如果相等,则测试通过;
Assert.Inconclusive() 表示一个未验证的测试;
Assert.IsTrue() 测试指定的条件是否为True,如果为True,则测试通过;
Assert.IsFalse() 测试指定的条件是否为False,如果为False,则测试通过;
Assert.IsNull() 测试指定的对象是否为空引用,如果为空,则测试通过;
Assert.IsNotNull() 测试指定的对象是否为非空,如果不为空,则测试通过;
我们通过对示例1 添加测试所需的初始值,并对断言进行简单的修改后,便得到一个正式的单元测试。
如示例2:
这样,便得到了一个正式的单元测试。用断言Assert.AreEqual()比较expected、actual是否相等。 如示例3:
测试项目的运行方式有两种: 代码覆盖是单元测试的一个关键指标。 注意: VSTS 在生成单元测试框架时,默认没有启用“代码覆盖”功能。 June 13 陈佩斯的花白胡子June 11 Format时间显示最近改一个VB的老项目,大量的用到了不同格式的时间显示,比较讨厌,虽然没什么技术含量,
但要用的时候还真是急死人,所以顺便把format的东西总结一下:
Format(Now, "...")
年: yy/yyyy 两位年/四位年 输出: 08/2008 月: m/mm 一位月两位月 输出:1/01 (1-12)/(01-12) mmm/mmmm 英文简写月/全称月 输出: Jan/January ooo ¦oooo 中文显示月 输出为:一月 日: dd/d ¦y 一位日/两位日 输出: 8/08 (1-31)/(01-31) 时: h/hh 一位时/两位时 输出: 9/09 (0-23)/(00-23) 分: n/nn 一位分/两位分 输出: 30/30 (0-59)/(00-59) 秒: s/ss 一位秒/两位秒 输出: 40/40 (0-59)/(00-59) 星期: aaa ¦aaaa 中文星期 输出:星期六 ddd/dddd 英文星期简称/全称 输出: Sat/Satday w ¦ww 用数字表示星期 输出:7 表示星期六,星期日为1 综合显示: c 以短时间格式显示时间 输出:2008-1-8 9:30:40 ddddd 以短时间格式显示年月日 输出:2008-1-8 dddddd 中文显示年月日 输出:2008年1月8日 ttttt 以长时间格式显示时间 输出:9:30:40 ampm 显示上午/下午 Format(Now,'ampm') 输出为:上午 差不多就这些了吧! May 19 三分钟从来没有这样被国人震撼过,三分钟,将永远留在我的心中。作为一个中国人。
街上静立默哀的人群,停车鸣笛车流
愿国人都能永远记住这一刻,愿国人自强!
无论身在何方,愿都为自己是中国人骄傲! 国殇天灾?人祸?
暂时不想也不愿去考虑
为地震中逝去的同胞默哀!!
逝者已矣,生者当坚强。
从5月12日以来,感受中国人的团结,和少数官员的良心,中国似乎还没有到不可药救的地步。从中央地反应,到身边每一个关心灾区的百姓,用我老婆的话说:第一次真正感觉到自己的爱国心复活了。中国还是有她的脊梁的。
中国人民从来就是伟大的,接下的重建希望我们的“老爷们”能真正负起责来,不要愧对全国乃至全世界华人的爱心,天灾过后,但愿没有人祸!
May 08 小丫头越来越无法无天了开始只是敢和妈妈对着来,现在竟然敢和爷爷对“打”了
估摸着那天好好教训一顿,狠下心在她小屁屁上啪几下,不然都不知道怎么带她了
不过可能还真下不了手,呵呵呵,可爱的小东西... April 26 一代佳人20年前的歌,20年后再一次听到:
胭脂红粉只能点缀青春 却不能掩饰岁月留下的伤痕 有甚麽可让我刻骨铭心 唯有你唯有你爱人 海誓山盟说是情深意浓 问谁真心为爱厮守一生 你有血你有泪淋漓尽致 那热情熨烫着我的一颗心 悲欢岁月浮华人生 难得有这一份情 让我在今生今世记忆深深 是我最心爱的人 胭脂红粉只能点缀青春 绝不能掩饰岁月留下的伤痕 有甚麽可让我刻骨铭心 唯有你唯有你爱人 海誓山盟说是情深意浓 问谁真心为爱厮守一生 你有血你有泪淋漓尽致 那热情熨烫着我的一颗心 悲欢岁月浮华人生 难得有这一份情 让我在今生今世记忆深深 你是我最心爱的人 让我在今生今世记忆深深 你是我最心爱的人 April 23 c#的com开发,比较烦
namespace PrintExe
[DispId(1)] bool WriteCommand(string com,string flag); [Guid("AC8C1E64-B501-4f8b-A026-B4F1D8EF7DF2")] OleDbConnection myConn = new OleDbConnection(connStr); private System.ComponentModel.Container components = null; public UserControl1() #region 元件設計工具產生的程式碼 } #region IOLpt1 成員 public bool WriteCommand(string com,string flag) Instruction = temp1.ToString(); if(myArray[i,2].Trim() != "") if(myArray[i,3].Trim() != "") public void WhenLoad() #endregion #region IObjectSafety 成員 public void GetInterfacceSafyOptions(Int32 riid, out Int32 pdwSupportedOptions, out Int32 pdwEnabledOptions) public void SetInterfaceSafetyOptions(Int32 riid, Int32 dwOptionsSetMask, Int32 dwEnabledOptions) #endregion February 25 周末陪丫头,开心小丫头精神恢复了不少,趁周末好好陪了她一下,买了些小玩具,丫头很开心,很久没看她笑得那么开心了,而且她很喜欢和我玩,让老爸我很是自豪一把。不过就是不愿意让我抱,想想原因,可能是住院的时候每次打针、换药什么的都是我抱她去,估计在她心里已经有了这样的概念:老爸一抱就不会有什么好事情。唉,这么点小就有心理阴影了,可怜的孩子,老天保佑,我的宝贝健健康康!!!! February 22 昨天被郁闷了一下昨天元宵节,公司没有提前下班。下班后急忙忙往家赶,半路接到电盈那边电话,大概意思是他们的项目有些延迟,如果我没有辞职就不要那么急,等一段时间在过去。而现实是我刚刚辞职了,娘的,也是被他们崔的要死才辞的,为了离职时间可以早点不晓得和领导摸了多少嘴皮子。现在竟然这样,怎一个郁闷可以形容。
今天打电话过去问个明白,结果又说没关系,还是按约定入职,早点过去也没什么,靠,什么意思吗? February 21 关于08年的一点想法新年了,虽然有个不是很好的开始,但是还是想对这一年做个畅想,08年很大压力的一年,不过应该也是一个可以有所突破的年程。
首先是雅思,希望可以最迟在6月份的时候通过。这样就可以在下半年开始申请,年底基本可以走完ACS评估,09年中应该就可以走了。如果可以这样就最好了,实在不行就多考两次,反正08年必须要过雅思,否则就手不过去了。
再就是换了新的工作,新环境,新同事,新项目。希望可以有所突破,起码如果出不了国,在国内还有一份不错的工作。
另外就是小丫头的身体实在不好,要想办法调理,这个小丫头从出生就没让我这个当老爸的消停过,但愿现在大一点了身体会好点。
三件大事,几乎压得我喘不过气,不过相信拼一把还是会有很大的突破的。老天保佑!!!!!! February 20 辞职了,终于要动一下了在数网干了差不多4年,付出努力和汗水,说实话收获和自己的付出不成比例。很早就打算走,一来是朋友的挽留,加上一些承诺,当然这些承诺都没实现。再就是要考雅思,在这边似乎可以有多谢时间学外语,其实不然,也忙得要死。新的东家已经找好,离职就直接过去,薪水比较合理,福利也比这边好了很多,只是刚过去可能会忙一些,没有多的时间复习。不过,时间这东西关键看自己,只要挤总还是有的。
上次雅思没有过,要努力了,时间不等人,过了30岁再移民感觉会多很多不确定的因素。加油!!!!! 丫头又手术了小丫头一岁生日又手术了,医生说是上次手术的并发症。进手术室的那一瞬间,我几乎要晕过去了。可怜的孩子,才那么小,我愿意这一切发生在我身上。我愿意替她受一切罪。老天保佑,思思永远健康!! September 25 C#异步编程2基于事件的异步模式是比 IAsyncResult 模式更高级的一种异步编程模式,也被用在更多的场合。对于相对简单的应用程序可以直接用 .Net 2.0 新增的 BackgroundWorker 组件来很方便的实现,对于更复杂的异步应用程序则需要自己实现一个符合基于事件的异步模式的类。这两者对我都是新东西,先从简单的入手,下一篇里我再去尝试复杂类模型的实现
模式概述 支持基于事件的异步模式的类会有若干个 MethodNameAsync 方法表示开始异步操作,并有对应的 MethodNameCompleted 事件。类里面还可能会有 CancelAsync或 MethodNameAsyncCancel 方法用于取消异步操作,并可以有 ProgressChanged 或 MethodNameProgressChanged事件来跟踪执行进度。下面分别作一下解释 MethodNameAsync 方法可以有两个重载:单调用和多调用,多调用有一个额外的状态对象参数 userState。userState 参数用来区分各次异步操作,使得我们可以多次调用多调用形式的方法而不需要等待任何异步操作的完成(在学习 IAsyncResult 模式时我把状态对象仅仅当成传给回调方法的一个条件来用,可能在使用模式时这么做并没有什么关系,但在实现模式时不把状态对象用作异常调用的唯一标识而另作他用就值得商榷了)。而单调用形式的方法如果在前一个调用尚未完成时调用将会抛出 InvalidOperationException 异常 如果有多个异步方法,则应使用 CancelAsync 方法来取消挂起的操作,并可使用 userState 来取消指定的挂起任务。如果只有一个异步方法则可以使用 MethodNameAsyncCancel 方法 另外 MSDN 上说:一次只支持一个挂起的操作的方法(如 Method1Async(string param))是不可取消的。这句话我还没有理解,不可能说是单调用的异步方法就不能取消吧,BackgroundWorker 上都是这样做的 先不管了,接着看ProgressChanged 事件。它有一个 ProgressChangedEventArgs 参数,事件处理程序通过检查该参数的 ProgressPercentage属性来获取任务完成的百分比。如果有多个异步操作挂起,也可以通过检查参数的UserState 属性来分辨操作。如果需要用 ProgressChanged 事件来报告增量结果,则可以把结果保存在派生自 ProgressChangedEventArgs 的类中,并在事件处理程序中使用 BackgroundWorker BackgroundWorker 很好的符合了事件异步操作模式。它有两个重载版本的 RunWorkerAsync 方法(均为单调用形式)和 RunWorkerCompleted 事件,并有 CancelAsync 方法以及 ProcessChanged 事件。不同的是 BackgroundWorker增加了 DoWork 事件,在 RunWorkerAsync 方法调用时发生,以达到将实际执行的开始方法与 BackgroundWorker 分离的目的。还需要提一下的是 WorkerReportsProcess 属性和ReportProcess 方法,前者指示能否报告进度更新,后者引发 ProcessChanged 事件,它们会在接下来的 Demo 里用到 尝试 因为平时经常要处理几十兆的文本文件,这个 Demo 就做一个读取文件并显示进度的控制台程序。先看类名和字段
构造函数接收文件路径为参数,设置文件路径并初始化 BackgroundWorker
接下来看这三个事件的处理程序。每一个事件都有各自的 EventArgs 参数类型,都很简单就不多说了 第一个 BackgroundWorker_DoWork 方法写得我有些郁闷。我在方法里取文件长度,先是直接取 StreamReader.BaseStream.Length 或 FileInfo.Length ,结果却导致很多文件读不到 100% 就结束了,不得已改成先把整个文件读一次得到字符串的长度。这样的方法当然性能不好了,主要是因为自己对 IO 一直就不够清楚,等下一个主题重新认识下 IO 再回头过来改吧。也望有经验的朋友赐教,感激不尽 BackgroundWorker_RunWorkerCompleted 方法,输出结果。这里要注意如果 RunWorkerCompletedEventArgs 参数的 Error 属性不为空则读取其他属性会产生异常,然后如果 Cancelled 属性为 true 则读取 Result 属性也会产生异常,因此必须依次判断各属性的值 /**//// <summary> 向外提供一个入口方法
最后是 Main 方法,比昨天有了小小的改变,用 Console.ReadLine 代替了 Thread.Sleep 来达到阻止主线程退出的目的
其他 回顾一下我用委托实现 IAsyncResult 模式的 Demo ,与用 BackgroundWorker 实现的基于事件的异步模式很相似吧。而且应用程序可以通过委托的 BeginInvoke 和 EndInvoke 方法来异步执行现有的同步方法而不需要作额外的修改,BackgroundWorker 也差不多是一样。我把这两者看成实现对应异步操作模式的范本,在性能要求不是很高的一些异步操作场合,用好委托和 BackgroundWorker 就可以简单有效的完成开发了 C#异步编程1。NET Framework 为异步操作提供了两种设计模式:使用 IAsyncResult 对象的异步操作与使用事件的异步操作。先来学习前者
概述 IAsyncResult 异步设计模式通过名为 BeginOperationName 和 EndOperationName 的两个方法来实现原同步方法的异步调用,如 FileStream 类提供了 BeginRead 和 EndRead 方法来从文件异步读取字节,它们是 Read 方法的异步版本 Begin 方法包含同步方法签名中的任何参数,此外还包含另外两个参数:一个AsyncCallback 委托和一个用户定义的状态对象。委托用来调用回调方法,状态对象是用来向回调方法传递状态信息。该方法返回一个实现 IAsyncResult 接口的对象 End 方法用于结束异步操作并返回结果,因此包含同步方法签名中的 ref 和 out 参数,返回值类型也与同步方法相同。该方法还包括一个 IAsyncResult 参数,用于获取异步操作是否完成的信息,当然在使用时就必须传入对应的 Begin 方法返回的对象实例 开始异步操作后如果要阻止应用程序,可以直接调用 End 方法,这会阻止应用程序直到异步操作完成后再继续执行。也可以使用 IAsyncResult 的 AsyncWaitHandle 属性,调用其中的WaitOne等方法来阻塞线程。这两种方法的区别不大,只是前者必须一直等待而后者可以设置等待超时 如果不阻止应用程序,则可以通过轮循 IAsyncResult 的 IsCompleted 状态来判断操作是否完成,或使用 AsyncCallback 委托来结束异步操作。AsyncCallback 委托包含一个 IAsyncResult 的签名,回调方法内部再调用 End 方法来获取操作执行结果 尝试 先来熟悉一下今天的主角,IAsyncResult 接口
我用一个 AsyncDemo 类作为异步方法的提供者,后面的程序都会调用它。内部很简单,构造函数接收一个字符串作为 name ,Run 方法输出 "My name is " + name ,而异步方法直接用委托的 BeginInvoke 和 EndInvoke 方法实现
首先是 Begin 之后直接调用 End 方法,当然中间也可以做其他的操作
也可以用 IAsyncResult 的 AsyncWaitHandle 属性,我在这里设置为1秒超时
不中断的轮循,每次循环输出一个 "."
最后是使用回调方法并加上状态对象,状态对象被作为 IAsyncResult 参数的 AsyncState 属性被传给回调方法。回调方法执行前不能让主线程退出,我这里只是简单的让其休眠了1秒。另一个与之前不同的地方是 AsyncDemo 对象被定义成了类的静态字段,以便回调方法使用
其他 对于一个已经实现了 BeginOperationName 和 EndOperationName 方法的对象,我们可以直接用上述方式调用,但对于只有同步方法的对象,我们要对其进行异步调用也不需要增加对应的异步方法,而只需定义一个委托并使用其 BeginInvoke 和 EndInvoke 方法就可以了 |
|
|