获取操作系统版本信息

坊间流传的代码都有些问题,比如不能正常获取win7以上的版本信息,不能获取诸如专业版,旗舰版等的信息,不能正常获取操作系统位的信息。 使用代码,写了一个简单的库来实现效果。用法大概如下: StringBuilder sb = new StringBuilder(String.Empty); sb.AppendLine("Operation System Information"); sb.AppendLine("----------------------------"); sb.AppendLine(String.Format("Name = {0}", OSVersionInfo.Name)); sb.AppendLine(String.Format("Edition = {0}", OSVersionInfo.Edition)); if (OSVersionInfo.ServicePack!=string.Empty) sb.AppendLine(String.Format("Service Pack = {0}", OSVersionInfo.ServicePack)); else sb.AppendLine("Service Pack = None"); sb.AppendLine(String.Format("Version = {0}", OSVersionInfo.VersionString)); sb.AppendLine(String.Format("ProcessorBits = {0}", OSVersionInfo.ProcessorBits)); sb.AppendLine(String.Format("OSBits = {0}", OSVersionInfo.OSBits)); sb.AppendLine(String.Format("ProgramBits = {0}", OSVersionInfo.ProgramBits)); textBox1.Text = sb.ToString(); 对比一下坊间的几种不足: 总的来说。最大的问题就是不能正确检测你的操作系统到底是32位还是64位。几种方法大致如下: 1. 使用IntPtr指针的大小 最关键的一句代码是: return IntPtr.Size * 8; 但是事实上,这个返回的不是操作系统的位数,返回的是运行的程序的位数,如果在64位的windows上以32位的模式运行了这个程序,那么就会返回32. 2. 使用PROCESSOR_ARCHITECTURE 环境变量 string pa = Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE"); return ((String.IsNullOrEmpty(pa) || String.Compare(pa, 0, "x86", 0, 3, true) == 0) ? 32 : 64); 这就是纯粹的误导了,因为和1的情况一样。不能返回处理器的位数而是返回了运行程序的位数,如果在64位的windows上以32位的模式运行了这个程序,那么就会返回32. 3. 使用PInvoke 和 GetSystemInfo 注意:为了保持文章不要太长。。我没有包括PInvoke API的声明,(译者注:C#的互操作性嘛),但你可能在我提供的源代码里找到。 ProcessorArchitecture pbits = ProcessorArchitecture.Unknown; try { SYSTEM_INFO l_System_Info = new SYSTEM_INFO(); GetSystemInfo(ref l_System_Info); switch (l_System_Info.uProcessorInfo.wProcessorArchitecture) { case 9: // PROCESSOR_ARCHITECTURE_AMD64 pbits = ProcessorArchitecture.Bit64; break; case 6: // PROCESSOR_ARCHITECTURE_IA64 pbits = ProcessorArchitecture.Itanium64; break; case 0: // PROCESSOR_ARCHITECTURE_INTEL pbits = ProcessorArchitecture.Bit32; break; default: // PROCESSOR_ARCHITECTURE_UNKNOWN pbits = ProcessorArchitecture.Unknown; break; } } catch { Ignore } return pbits; 老问题,还是会返回运行程序的位数,而不是操作系统/处理器的位数。 4. 使用PInvoke和GetNativeSystemInfo 我看到过有人说上面的都不可信。可以使用GetNativeSystemInfo代替,代码和上面一样,只是把GetSystemInfo换成GetNativeSystemInfo就好。 ...

2012-11-23 · 2 min · bystander

解决win8无法上网的问题

昨天晚上@虎振兴同学装了win8.。结果悲剧了。症状为连接宽带可以连接上。上qq也正常。但是。只要打开网页。就会自动断网。再连接就会提示651错误了。网上大多说是驱动不兼容。但是解决的方法大部分是不对的。下面结合网上的给大家说一说。。 网卡驱动目测是都是美满公司,也就是Marvell 的Yukon系列网卡驱动的问题。首先下载一个旧版本的驱动(32位下载/64位下载) 然后按下图操作,第一步是打开计算机-管理。。各种姿势只要打开了计算机管理就可以了。 在这里稍微记一下这个名字。Marvell Yukon 88exxxxx PCI-E Fast Ethernet.. 找到网络适配器,右键更新驱动程序。 注意记下兼容的网卡。名字和第二步的差不多的那个,点击从磁盘安装,选择下载后驱动的解压的安装文件,如图 到这一步以后,点击打开,可能会出现一个驱动列表。这是时候选择一个和兼容列表名字一样的。88e这部分不一样。如果找不到,也可以找类似的,比如途中给出的后两位是39.我装的是40也没问题。这个是驱动的历史版本。然后就可以了 最后。提醒各位童鞋。win8整体还是很不错的。不过呢。对于我来说。metro界面和正常的界面的傻傻分不清楚的模式。令我很是蛋疼。。所以暂时没有考虑换到win8.。。

2012-11-21 · 1 min · bystander

依赖倒置原则和依赖注入模式

昨天读完了程杰的《大话设计模式》。。收获颇丰。深刻感到了设计模式的伟大。。对面向接口的编程也理解了不少。刚好看到codeproject上一篇将依赖倒置的。讲到了依赖注入的方式。仔细读了一下。翻译一遍加深认识。 高耦合的代码随着项目复杂性的不断增加,最终会变成一碗碗的意大利面条啦。。二者通常是软件设计上的问题,如果一个类对另一个类的实现了解太多。当该类改变的时候会引起更多的改变。这违反了依赖倒置原则 而松耦合的代码设计优良。随着时间流逝,代码复杂两增大,松耦合的好处会变得更加清晰,依赖注入模式是实现松耦合的一个好的办法,本文介绍在没有依赖注入容器的情况下实现依赖注入 GoF说了,依赖倒置的原则: 高层模块不应依赖于低层模块,他们都应该依赖于抽象 抽象不依赖细节,细节依赖抽象 刚开始写依赖倒置比较难,随着经验增长会有所改善,通过使高层模块依赖于抽象,依赖倒置成功解耦,依赖注入模式是该原则的一个实现。 通常我们写出如下的代码: public class Email { public void SendEmail() { // code } } public class Notification { private Email _email; public Notification() { _email = new Email(); } public void PromotionalNotification() { _email.SendEmail(); } } Notification类依赖Email类,这违反了DIP,而且当我们要发送短信/保存到数据库的时候,我们还要改变Notification类。 我们使用抽象类/接口解耦 public interface IMessageService { void SendMessage(); } public class Email : IMessageService { public void SendMessage() { // code } } public class Notification { private IMessageService _iMessageService; public Notification() { _iMessageService = new Email(); } public void PromotionalNotification() { _iMessageService.SendMessage(); } } IMessageService 是一个接口,而Notification 类只要调用接口的方法/属性就可以了 同时,我们把Email对象的构造移到Notification 类外面去。 依赖注入模式可以实现。通常有三种方式 构造器注入 属性注入 方法注入 构造器注入 最普遍的方式,当一个类需要另一个类的依赖的时候,我们通过构造函数来提供,现在我们这样写 public class Notification { private IMessageService _iMessageService; public Notification(IMessageService _messageService) { this._iMessageService = _messageService; } public void PromotionalNotification() { _iMessageService.SendMessage(); } } 有几个好处:1.构造函数实现很简单,Notification类需要知道的很少。想要创建Notification实例的时候看构造函数就可以知道需要什么信息了。因此实现了松耦合。 属性注入 属性注入/setter注入比较不常见,当依赖可有可无的时候很有用。我们暴露一个可写的属性,允许客户提供不同的依赖实现,比如这样。 public class Notification { public IMessageService MessageService { get; set; } public void PromotionalNotification() { if (MessageService == null) { // some error message } else { MessageService.SendMessage(); } } } 没有了构造函数。而用属性来替换,在PromotionalNotifications 方法里我们需要检查MessageService的值或者提供相应的服务。 ...

2012-11-21 · 1 min · bystander

C#中的throw

Throw会抛出/传递异常,通过在catch块里使用throw语句.可以改变产生的异常,比如我们可以抛出一个新的异常,throw语句有各种各样的,并且很有必要. 例子 我们首先看一下三个方法,分别叫做A,B,C,他们使用不同的throw语句。方法A使用了无参的throw语句。这可以被看作是rethrow(继续抛出)—他会抛出已经出现的同样的异常 继续,方法B throw一个命名的异常变量。这就不是一个完全的rethrow了—因为他虽然抛出了同样的异常。但是改变了StackTrace(堆栈轨迹),如果有必要的话,我们可以收集一些异常信息,而方法C则创建了一个新的异常。 提示:你可以通过这种方法实现自定义的的错误处理 使用throw语句的例子 using System; class Program { static void Main() { try { A(); B(); C(null); } catch (Exception ex) { Console.WriteLine(ex); } } static void A() { // Rethrow 语法. try { int value = 1 / int.Parse("0"); } catch { throw; } } static void B() { // 过滤异常类型. try { int value = 1 / int.Parse("0"); } catch (DivideByZeroException ex) { throw ex; } } static void C(string value) { // 创建新的异常. if (value == null) { throw new ArgumentNullException("value"); } } } 程序可能的输出结果 System.DivideByZeroException: Attempted to divide by zero. System.DivideByZeroException: Attempted to divide by zero. System.ArgumentNullException: Value cannot be null. Parameter name: value Rethrow 接着我们看更多的关于rethrows的细节。Rethrow必须是一个无参的throw语句。如果使用throw ex,那么TargetSie(TargetSite 从堆栈跟踪中获取抛出该异常的方法。如果堆栈跟踪为空引用,TargetSite 也返回空引用。-译者注)和StackTrace都被改变了。 在下面的程序里,X()方法使用了rethrow语句。Y()使用了throw ex语句。我们可以看看当rethrow语句使用的使用,引发异常的方法,也就是异常的TargetSite是在StringToNumber—一个int.Parse内部的方法。 但是:当throw ex用的时候。就像在Y()里面,这个异常的TargetSite被修改到了当前的Y()方法里。 测试rethrow的例子 using System; class Program { static void Main() { try { X(); } catch (Exception ex) { Console.WriteLine(ex.TargetSite); } try { Y(); } catch (Exception ex) { Console.WriteLine(ex.TargetSite); } } static void X() { try { int.Parse("?"); } catch (Exception) { throw; // [Rethrow 构造] } } static void Y() { try { int.Parse("?"); } catch (Exception ex) { throw ex; // [Throw 捕获的ex变量] } } } 输出 ...

2012-11-18 · 1 min · bystander

理解并实现模板模式

介绍 本文实现模板模式 背景 有时候我们需要做很多任务,而做这些任务的算法可能不同,这样可以设计成策略模式,这样。执行该任务的基本的一些代码就是一样的。但程序可可以动态的切换来执行任务的不同部分了。 现在,真实的情况是有些算法,从实现层面山看,有可能有一些步骤是不一样的,这种情况下。我们可以使用继承来完成。 当有个算法,而这个算法的一部分却多样的时候。使用模板模式就很好。GoF定义模板模式为: “Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm’s structure.”. 定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板模式使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。 在上面的类图中: AbstractClass:包含两种方法。第一种就是算法的每一步。另一种就是模板方法。模板方法就是那些可以被用在所有独立方法中。并且提供了算法执行的一个骨架 ConcreteClass:这个类重写了抽象类中每一步的方法,包含对这些步骤的个性化实现。 使用代码 看一个简单的例子。假想我们有一个类用来读取数据。并且能够为信息管理系统到处数据。 abstract class DataExporter { // 这个方法都是一致的 public void ReadData() { Console.WriteLine("Reading the data from SqlServer"); } // 当报表格式顶的时候这个也是定的。 public void FormatData() { Console.WriteLine("Formating the data as per requriements."); } // 目标文件类型的不同导致该方法不同 public abstract void ExportData(); // 这是客户端可能使用的模板方法 public void ExportFormatedData() { this.ReadData(); this.FormatData(); this.ExportData(); } } ReadData和FormatData 的实现不会变。唯一可变的部分就是ExportData方法。该方法对于不同的导出类型不同。如果我们要导出excel文件。我们要实现一个ConcreteClass的实现。 class ExcelExporter : DataExporter { public override void ExportData() { Console.WriteLine("Exporting the data to an Excel file."); } } 同样如果要导出PDF文件。重写这部分即可 class PDFExporter : DataExporter { public override void ExportData() { Console.WriteLine("Exporting the data to a PDF file."); } } 好处就是客户端可以使用DataExporter类,而具体的实现是在派生类中的 static void Main(string[] args) { DataExporter exporter = null; //导出 Excel文件 exporter = new ExcelExporter(); exporter.ExportFormatedData(); Console.WriteLine(); // 导出 PDF 文件 exporter = new PDFExporter(); exporter.ExportFormatedData(); } 运行时。对算法的调用将会执行真正请求的派生类的方法。 看一下我们的类图 ...

2012-10-25 · 1 min · bystander

理解并实现外观设计模式

介绍 本文介绍外观模式,并给出简单的实现示例 背景 写软件的时候,有时候需要处理一系列的对象来完成一个确定的任务.比如,我们给一个万能遥控器写代码,我们需要关掉所有的设备,那么,我们有这样几种选择.第一个就是手动选择每一个设备,然后一个接一个的关闭,这好傻.那我们为什么不再遥控器上放一个按钮,我们按一下就关掉了.按钮的命令会与设备控制器通信然后关掉他们. 如果我们又想在晚上12的时候自动关闭设备,那么我们就会有一个基于事件的计时器,与设备通信,然后关闭设备,问题是在两种情况下我们都需要与这些对象通信的函数. 有很多方法解决这个问题,为什么不能有一个对象,该对象的责任就是关闭设备,当我要关闭设备的时候,我调用该对象就行了.这也是外观模式的理念Gof大神定义外观模式 “Provide a unified interface to a set of interfaces in a subsystem. Façade defines a higher-level interface that makes the subsystem easier to use.” 为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。 看看模式图 注意外观对象仅仅是提供了对函数一起操作,.不能替换子系统的接口.子系统的类仍然可以被系统的其他部分访问.外观为子系统提供了一致的界面. 使用代码 为了模拟外观模式,我们模拟一个小例子.试着实现一个简单的外观对象,该外观对象操作一些WP手机的控制器对象,我们先定义问题 每天早上我跑步的时候,我都得对我的手机做出以下的事情.. 1. 关闭wifi 2. 切换到移动网络 3. 打开GPS 4. 打开音乐 5. 开始跑步追踪器 跑完以后.,我又蛋疼的做出以下几件事 1. 在twitter和facebook上分享我的跑步数据 2. 关闭跑步追踪器 3. 关闭音乐 4. 关闭GPS 5. 关闭移动数据 6. 打开wifi 目前我都是手工做的.,我们来实现这些假想的控制器类吧. class GPSController { bool isSwitchedOn = false; public bool IsSwitchedOn { get { return isSwitchedOn; } set { isSwitchedOn = value; DisplayStatus(); } } private void DisplayStatus() { string status = (isSwitchedOn == true) ? "ON" : "OFF"; Console.WriteLine("GPS Switched {0}", status); } } 其他的像MobileDataController, MusicController, WifiController 代码都是基本的一样的. 然后模拟一下跑步追踪器这个app class SportsTrackerApp { public void Start() { Console.WriteLine("Sports Tracker App STARTED"); } public void Stop() { Console.WriteLine("Sports Tracker App STOPPED"); } public void Share() { Console.WriteLine("Sports Tracker: Stats shared on twitter and facebook."); } } 下面模拟一下我的手工过程 ...

2012-10-23 · 3 min · bystander

理解并实现装饰器模式

背景 本文讨论装饰器模式,这个模式是因为很多情况下需要动态的给对象添加功能.比如我们创建了一个Stream类.后来需要对这个数据流类动态的添加一个加密功能.有人可能说把加密方法写到流类里面啊.然后使用一个bool变量来控制开关就行了.但是这样.这个加密方法只能写一种..如果用派生类来实现.那么..对于不同的加密方法.,都要创建一个子类,举个例子.比如有时候是一些函数的组合.我们最终的派生类的数目基本上就和排列组合的数目一样了. 我们使用装饰器模式来解决这个问题.GoF描述为 “Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.” 首先看一下图.理解一下这个模式中每一个类的作用 • Component:定义了可以动态添加功能的具体类ConcreteComponents的接口. • ConcreteComponent: 可以动态添加功能的具体类 • Decorator: 定义了动态添加到ConcreteComponent类中的功能的接口 • ConcreteDecorator: 可以添加到 ConcreteComponent.中的具体功能类. 使用代码 我们开一个面包店的例子.面包店卖蛋糕和甜点.客户可以买蛋糕和甜点,同时添加一些额外的东西.额外的东西包括奶油(Cream),樱桃(Cherry),香料(Scent)和会员(Name Card) 如果我们用派生类来实现..那么我们会有如下的类 • CakeOnly • CakeWithCreamAndCherry • CakeWithCreamAndCherryAndScent • CakeWithCreamAndCherryAndScentAndNameCard • CakeWithCherryOnly • PastryOnly • PastryWithCreamAndCherry • PastryWithCreamAndCherryAndScent • PastryWithCreamAndCherryAndScentAndNameCard • PastryWithCherryOnly • 等等等等 这简直就是噩梦..我们用装饰器模式来实现把. 首先定义Component 接口 public abstract class BakeryComponent { public abstract string GetName(); public abstract double GetPrice(); } 前面说过了.这个类定义了能够动态添加功能的具体类(ConcreteComponents)的接口,好吧.然后来创建具体类ConcreteComponents class CakeBase : BakeryComponent { // 真实世界里,这个值应该来自数据库等 private string m_Name = "Cake Base"; private double m_Price = 200.0; public override string GetName() { return m_Name; } public override double GetPrice() { return m_Price; } } class PastryBase : BakeryComponent { //真实世界里,这个值应该来自数据库等 private string m_Name = "Pastry Base"; private double m_Price = 20.0; public override string GetName() { return m_Name; } public override double GetPrice() { return m_Price; } } 现在基对象准备好了.看看那些可以被动态添加的功能.我们看看Decorator 类 ...

2012-10-22 · 2 min · bystander

Android开发获取Map API Key

地图应用使用com.google.android.maps这个包。通过MapView控件使用。但是之前需要申请一个用于开发的API Key,这个key会和当前的计算机用户绑定。然后通过这个key去官方申请就可以拿到一个开发用的api key了 <1>首先找到用户的debug.keystore文件,可以再”运行“里面搜debug.keystore;如:c:\users\Administrator.android\debug.keystore <2>接下来获取MD5指纹,网上很多说的有误。貌似新版默认是出现sha1加密的。通过添加-v 参数会显示所有。 首先运行cmd,在dos界面里,输入 keytool -list -v -keystore c:\users\Bystander\.android\debug.keystore 命令,然后会让你输入keystore密码, 输入:android,之后,会出现指纹认证MD5,如下: <3>去官方生成真正的api key 访问 Sign Up for the Android Maps API 输入那串值,同意条款,确定后要求用Google帐号登录。然后会拿到一个key。ok

2012-10-21 · 1 min · bystander

关于爱情和爱情的附加值

 看到一篇好文。出处未找到。分享之。如果你不能静下来看完。那么就看我画出来的部分吧。 我一直在想,假如查尔斯王子只是一个普通的男人,那么19岁的戴安娜还会在明知他另有所爱的情况下嫁给他吗?在戴安娜一段被公开的录音带中,她曾经说大婚那天是她生命中最糟糕的一天——“我的心像死一样平静,我感觉自己像待宰的羔羊。” 她其实是可以不必那么可怜的,没有人把她送到案板上,是她自己愿意的。如果她不肯,谁还会强迫她站在教堂里对另一个男人说“我愿意”,是她自己说的。但是能责怪她吗?假如换着是我,我是不是也会说“我愿意”呢?我能分得清楚我是在对一个比自己年长很多而又与前情人藕断丝连的男人说“我愿意”,还是对那一顶令人羡慕的未来王冠说“我愿意”?即使当时年幼,戴安娜分不清楚这二者的区别,但后来她实际上也是有很多机会的。当他与查尔斯王子名存实亡以后,她是可以选择离婚的,但是她迟迟不肯,即使全世界都知道他们感情不在,她依然固执的要求保留“王妃”的头衔。也许是她已经习惯被称为“戴安娜王妃”,也许是她觉得自己为这个称号付出了太多,所以她不能失去这一荣誉。 据说英国电视台要以查尔斯、戴安娜和卡米拉的故事为蓝本拍一个片子,名字叫《爱情究竟是什么》。是呀,敢问情是何物,竟叫人生死相许? 我是读着《简·爱》长大的,我的爱情启蒙就是那个出生卑微的女教师对身份高贵的男主人说的那段话:“你以为我穷,不美,就没有感情吗?我也有的,假如上帝赐予我美貌与财富,我一定会使你难以离开我,正如我现在难以离开你,上帝没有这样做,但是我们的精神是平等的……” 待我长大一点,我冷不丁地想:如果上帝赐予简·爱小姐美貌与财富,她还会爱上那个又老脾气又坏的罗切斯特先生吗?不要责怪女人对爱情的态度,除了七仙女,没有几个女人会看上卖身为奴的董永。七仙女不食人间烟火,她有神仙血统,人间名利对于她来说,只要她想要,还不是唾手可得?她要的是一个她喜欢的男人,只要她喜欢就够了。你挑水我浇园,夫妻恩爱不夜天。对于七仙女来说,爱就是一件简单得不能再简单的事情。她不指望从爱情中再捞到些别的,因为别的,她可以用别的方式得到,惟有爱情本身是不可替代的。 但是对于我们寻常女子来说,我们能做得到吗?喜欢上一个男人,就跟他欢天喜地?我相信许多人是做不到的,因为我们对爱情的指望太多,我们期待从爱情中得到“附加值。我们对自己说,世上没有无缘无故的爱,如果爱一个人,不能给自己带来提升,为什么要爱他呢?甚至有许许多多的爱情指南大大方方地告诉我们:干得好不如嫁得好,为什么不能一举两得?嫁一个优秀的男人,既得到爱情又得到财富。是呀,为什么不呢?问题是世界上哪里有那么多便宜事?即使美丽如戴安娜王妃都无法如愿,何况我们呢? 要女人在一开始就分清楚,爱一个人,还是爱一个人所能提供的生活,这是很难的。跳水公主郭晶晶在被问到与富家公子的关系时,她说:“我爱一个男人不是爱他的钱,而是他的修养。”听到她这话的人都笑了:“原来不是为钱啊,如果那个男人是一个穷光蛋,你会发现他有修养吗?” 看过李少红拍的一部电视剧《橘子红了》,当中有一个周迅扮演的角色,名字叫秀禾。她本是一个穷人家的女孩子,为了改善家庭经济,缓解家人负担,自愿嫁到富人家里做三姨太,因为样貌可爱深得老爷喜欢,但是她在满足了一切物质需要以后,她发现自己真正爱的人是老爷的弟弟。 女人总是这样的,常常听女人评论什么样的男人不值得爱,她们往往会撇着嘴说,那些不成功没有经济能力的男人是不能嫁的,他们缺乏富人的风度和心胸。其实女人自己何尝不是这样?那些没有尝过富裕生活滋味的女人,有几个能像张曼玉那样,冷冰冰的抛出一句台词:“你有钱有什么了不起?我也有啊!” 在年少无知的时候,常常搞不懂富人家的女人为什么会偷情。尤其是封建社会,那是一旦被发现就要沉塘的死罪,可是为什么女人会冒着生命风险去做这等事情?就像秀禾,嫁给老爷之前,她的幸福愿望就是能得到老爷的宠爱,能对得起大太太的照顾,但是当她轻而易举地得到这一切以后,她却发现自己很痛苦。甚至比嫁入豪门之前还痛苦,那时她不过是穷,但是现在她觉得不自由,因为她没有爱情。 爱情究竟是什么?这个世界上到底是否存在纯粹的爱情?是什么让罗密欧与朱利叶生死相随?是什么让温莎公爵舍弃江山和王位?难道真的是因为他们幼稚或一时冲动吗?我相信不是。爱是一种无法替代的感情,除了和你爱的人在一起,否则你无法感受到爱的幸福。但是爱情的附加值则是可以替代的,如果你希望通过爱情而获得财富,那么当你获得财富以后,你就不认为你还需要和那个财富的提供者在一起。尤其当你借此成长起来,并且建立了自己的财富王国,你就不愿再忍受当初那个“男人”。因为你自己也有了,所以他在你的生活中很快就会成为一个多余的人,一个碍手碍脚的人,一个妨碍你追求幸福和自由的人。 出生于法国的英国作家毛姆曾经说过:“感情有理智所根本不能理解的理由。”他在传世之作《月亮和六便士》(卓越 当当 京东)中描写了一个名叫爱施略夫的男人,那是一个从任何一个角度讲都称得上是“好丈夫”的男人。他有钱,给妻子提供了安逸的生活,他对妻子很好,什么事情都由着她的心思。而她的妻子对他也一直很不错,直到有一天,他的妻子遇到一名穷困潦倒生活不能自理的画家。这名画家的原型据说是高更。人们都谴责这名画家勾引了这名良家妇女,但是毛姆另有解释,原话摘录如下:“过去我认为她爱施特略夫,实际上只是男人的爱抚和生活的安适在女人身上引起的自然反应。大多数女人都把这种反应当爱情了。这是一种对任何一个人都可能产生的被动的感情,正像藤蔓可以攀附在随便哪株树上一样。因为这种感情可以叫一个女孩子嫁给任何一个需要她的男人,相信日久天长便会对这个人产生爱情,所以世俗的见解便断定了它的力量。但是说到底,这种感情是什么呢?它只不过是对有保障的生活的满足,对拥有家资的骄傲,对有人需要自己沾沾自喜,和对建立起自己的家庭洋洋得意而已。女人们秉性善良、喜爱虚荣,因此便认为这种感情极富于精神价值。但是在冲动的热情面前,这种感情是毫无防卫能力的。” 女人在爱一个男人的时候,到底是更爱这个男人本身,还是爱他所能提供的生活品质?当女人一无所有的时候,那些爱情的附加值将对女人具有极大的诱惑力,但是当她自己成长起来,足够强大到凭自己的能力也可以得到梦想的生活时,那些所谓的附加值在女人眼里就一钱不值了。凡是通过努力通过购买可以得到的东西,独立女性在成功以后也是可以享受得到的,为什么要靠男人?但是爱情却是可遇不可求的,好容易在茫茫人海中看到一个如意的人,那种冲动就像七仙女看到董永一样,她一定是迫不及待地下凡,因为惟有下凡,才体会得到凡间的快乐。 我一个女性朋友,有一段时间一直犹豫不决。两个男人她都喜欢,男人甲与她青梅竹马,男人乙与她邂逅相逢。男人乙是一公司的高级职员,有车有房经常带她去吃西餐,男人甲在一名不见经传的公司做文案,骑自行车租地下室偶尔在外面吃一顿,也都是马兰拉面麦当劳。她很苦恼,她说喜欢与男人甲在一起的感觉,虽然穷,但是总是有很多话很快乐很亲密,但是她不喜欢与男人甲在一起的生活。虽然男人甲对她保证两年内就可以攒足房子的首付,但是要等两年,而且那房子一定是四环以外的。至于男人乙,她喜欢他所提供的生活,但是她觉得他很闷,与他在一起她总是很紧张,连吃西餐刀叉的姿势都在家练了又练。我们说,你可以等一等,不用很着急呀。但是她很着急,我知道她急什么,她等不得,她要立刻兑现。既然这样,她当然要选择那位经常能带她去吃西餐的男人乙了,因为对于她来说,这样的男人属于现钞。 也许因为男人乙很闷吧,再加上高级职员的工作很忙,她婚后仍有大把时间。她是一个很努力的女人,大部分时间都用来进修,反正老公有钱,那么学习总不是错吧?之后她跳槽,升职,加薪,她轻而易举地买了自己想买的房子,但是她却不肯与自己的老公分享,因为他没有爱的价值。 不要说我的朋友不痛苦,她如果不痛苦她就不会找我倾诉了。她想再找回当年的感情,但是那难度比找回去年的雪还大。她常常抱怨,我当时为什么这么傻?不就是一个三环边的房子和一辆富康车吗?不就是几顿小情小调的西餐吗?我就答应和他生活一辈子,一辈子是多长的时间啊! 我们都不能否认爱情中除了有爱情还有其他的东西,自古以来就有无数女人通过爱一个男人而彻底改变自己命运的例子,那些女人到底是幸运还是不幸?我想假如她们像从来没有吃过禁果的夏娃,或者像从来没有向人间偷窥的七仙女,她们也许是幸运的,因为她们不知道什么叫爱情。她们以为爱情就是她们已经得到的生活,但是千万不要让她们接触到任何与爱有关的事物,那会大大刺激她们的。她们在刺激之下,会觉得自己是最可怜的女人。就像查泰莱夫人一样,丈夫那样有地位有身份,但是当她懂得什么叫世间的爱之后,她还是义无返顾抛家舍业。因为她知道,那种爱是无法替代的,是物质生活不能补偿的。我不希望你像查泰莱夫人一样,在忍受那么多屈辱、不幸、心灵的折磨之后,才奔向情人的怀抱。你原本是没必要给自己找那么多麻烦的, 一个你不爱的男人,即使一切都好,又能好到哪里去呢?无非是他能给一些你现在还得不到的生活品质,但是如果你对自己有信心,那些所谓的生活品质是很难达到的吗?也许现在你会为一个肯送你路易威登手提袋的男人而心动,但是当你自己可以到巴黎总店随便挑选的时候,你还会为那个男人心动吗?你还会因为他送得起这样一个昂贵的包而凭空给他打几个高分吗? 世间值得追求的东西很多,但惟有爱情,是必须真心相爱才可以尝到它的滋味的。而其他的东西,你得到它的途径其实有很多,并不一定非要通过和一个人结婚才可以得到。既然这样,你为什么要给自己的爱设定那么高的门槛?我担心的不是你对爱的要求太高,我是担心迈得进你门槛的人,恰恰都是与爱无关的人。因为真爱是不需要门槛的,而且也不屑于门槛。爱是两情相悦,你情我愿,又不是在自由市场挑西红柿,非要找性能价格,比最合理的。 恋人之间最爱问的一句话,大概就是“你爱我什么?”从来没有人会说我爱你的钱,你的财富,你所能给我提供的生活,为什么?因为我们都知道那太煞风景。至今为止,我听到的最动人的答案是一句英文:“I LOVE YOU NOT BECAUSE OF WHO YOU ARE,BUT BECAUSE OF WHO I AM WHEN I AM WITH YOU.”我不知道如何把它翻译得浪漫多情,但是我想即使是直截了当的翻译,那其中的真情也足以动人:我爱你,并不是因为你是谁,而是因为和你在一起时,我才是最真实的我。 [text]PS:私自觉得那句英文应该翻译为:我爱你,不是因为你是谁,而是因为我在你面前可以是谁。[/text]

2012-10-20 · 1 min · bystander

理解并实现原型模式-实现ICloneable接口.理解深浅拷贝

本文用C#实现原型模式,也会讨论深浅拷贝,已经如何在.net中高效实现ICloneable 接口 介绍 有时候我们需要从上下文得到一个对象的拷贝,然后通过一些独立的操作来处理他。原型模式在这种情况下很适用 GoF 定义原型模式为用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。 Specify the kind of objects to create using a prototypical instance, and create new objects by copying this prototype." 看一下类图 主要的参与者有 • Prototype: 抽象类或接口,定义了方法来拷贝自己 • ConcretePrototype: 克隆的具体类. • Client: 需要执行拷贝对象的软件对象 然后实现吧 使用代码 为了简化。我以一个著名的偷车游戏作为例子 我们说游戏里有一个注脚。这个主要有着一些定义游戏数据的统计量。保存游戏的时候我们就需要拷贝这个对象,然后序列化到文件中。(仅仅是举个例子,真实的游戏里很少这样做) 下面这个类抽象类就是概念中的Prototype public abstract class AProtagonist { int m_health; int m_felony; double m_money; public int Health { get { return m_health; } set { m_health = value; } } public int Felony { get { return m_felony; } set { m_felony = value; } } public double Money { get { return m_money; } set { m_money = value; } } public abstract AProtagonist Clone(); } 接口定义了玩家重要的信息,然后定义了一个Clone方法。然后我们定义一个具体的玩家类CJ。这样我们可以克隆当前对象,然后异步的进行序列化 class CJ : AProtagonist { public override AProtagonist Clone() { return this.MemberwiseClone() as AProtagonist; } } 这个类就是概念中的ConcretePrototype 。这里为了简化也没有其他一些方法了。 现在看看客户端软件的写法 static void Main(string[] args) { // 演示原型模式 CJ player = new CJ(); player.Health = 1; player.Felony = 10; player.Money = 2.0; Console.WriteLine("Original Player stats:"); Console.WriteLine("Health: {0}, Felony: {1}, Money: {2}", player.Health.ToString(), player.Felony.ToString(), player.Money.ToString()); // 这里是拷贝部分. CJ playerToSave = player.Clone() as CJ; Console.WriteLine("\nCopy of player to save on disk:"); Console.WriteLine("Health: {0}, Felony: {1}, Money: {2}", playerToSave.Health.ToString(), playerToSave.Felony.ToString(), playerToSave.Money.ToString()); } ...

2012-10-19 · 3 min · bystander