远程管理Demo(C#)

一个C#的通信的例子 1.服务端,服务端通过ip和端口生成客户端之后,点击开始监听后,便开启监听线程持续监听,同时注册断开连接和收到信息的事件。收到来自TcpClient 流中的信息后,解析之,如果是连接信息,就添加到连接列表,这样服务端就可以显示多个客户端了。如果是断开信息,就删掉。如果服务端想要给客户端发消息,就选中该客户,然后填写信息,就会调用连接类的发送方法。 2.客户端,也就是被控端,被控端通过tcp连接到远端ip,然后发送连接成功状态,随后异步读取。读取到信息后调用解析方式。然后处理。。 3.服务端如何生成客户端。其实也比较简单。就是写好客户端以后,保存为文本。然后通过CodeDomProvider的相关方法来编译即可。代码如下: public static bool Compile(string EXE_Name, string Source) { CodeDomProvider Compiler = CodeDomProvider.CreateProvider("CSharp"); CompilerParameters Parameters = new CompilerParameters(); CompilerResults cResults = default(CompilerResults); Parameters.GenerateExecutable = true; Parameters.OutputAssembly = EXE_Name; Parameters.ReferencedAssemblies.Add("System.dll"); Parameters.CompilerOptions = " /target:winexe"; Parameters.TreatWarningsAsErrors = false; cResults = Compiler.CompileAssemblyFromSource(Parameters, Source); if (cResults.Errors.Count > 0) { foreach (CompilerError CompilerError_loopVariable in cResults.Errors) { CompilerError error = CompilerError_loopVariable; MessageBox.Show("Error: " + error.ErrorText, "", MessageBoxButtons.OK, MessageBoxIcon.Error); } return false; } else if (cResults.Errors.Count == 0) { return true; } return true; } 源码下载:CSharp RAT Example.zip

2013-01-04 · 1 min · bystander

如何创建WPF用户控件&在WPF项目中使用

作者给的Demo我合并了下。VS2010直接打开解决方案。二者都有。 介绍 本文展示在WPF中如何创建用户控件并且如果在WPF项目中使用。我将使用VS2008和C#来展示如何创建一个自定义的ToolTip 背景 这篇由Sacha Barber.写的和我的有点像。 使用代码 开始。首先,我们创建一个用户控件。因此,我们选择新建WPF用户控件类库(WPF User Control Library)。 现在。我们可以创建或者编辑XAML代码来创建自定义的用户控件了。我使用XAML来创建自定义的ToolTip。你想做什么随你。 <UserControl Name="UserControlToolTip" x:Class="CustomToolTip.UserControl1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" RenderTransformOrigin="0,0" HorizontalAlignment="Left" VerticalAlignment="Top" > <UserControl.RenderTransform> <TransformGroup> <ScaleTransform ScaleX="1" ScaleY="1"/> <SkewTransform AngleX="0" AngleY="0"/> <RotateTransform Angle="0"/> <TranslateTransform x:Name="UserControlToolTipXY" X="0" Y="0"/> </TransformGroup> </UserControl.RenderTransform> <Grid HorizontalAlignment="Center" VerticalAlignment="Center" MinWidth="200" MinHeight="120"> <Grid.RowDefinitions> <RowDefinition Height="0.333*"/> <RowDefinition Height="0.667*"/> </Grid.RowDefinitions> <Rectangle Fill="#FFFBFBFB" Stroke="#FF000000" RadiusX="10" RadiusY="10" RenderTransformOrigin="0.139,0.012" StrokeThickness="1" Grid.RowSpan="2"> <Rectangle.BitmapEffect> <DropShadowBitmapEffect Opacity="0.8"/> </Rectangle.BitmapEffect> </Rectangle> <Rectangle RadiusX="10" RadiusY="10" RenderTransformOrigin="0.139,0.012" StrokeThickness="10" Stroke="{x:Null}" Margin="1,1,1,1" Grid.Row="0" Grid.RowSpan="2"> <Rectangle.Fill> <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0.725"> <GradientStop Color="#00E6D9AA" Offset="0.487"/> <GradientStop Color="#FFE6D9AA" Offset="0.996"/> </LinearGradientBrush> </Rectangle.Fill> </Rectangle> <Rectangle RadiusX="10" RadiusY="10" RenderTransformOrigin="0.493,0.485" StrokeThickness="10" Stroke="{x:Null}" Grid.RowSpan="2" Margin="1,1,1,1"> <Rectangle.Fill> <LinearGradientBrush EndPoint="0.014,0.5" StartPoint="0.211,0.5"> <GradientStop Color="#00E6D9AA" Offset="0.513"/> <GradientStop Color="#FFE6D9AA" Offset="0.996"/> </LinearGradientBrush> </Rectangle.Fill> </Rectangle> <Rectangle RadiusX="10" RadiusY="10" RenderTransformOrigin="0.493,0.485" StrokeThickness="10" Stroke="{x:Null}" Grid.RowSpan="2" Margin="1,1,1,1"> <Rectangle.Fill> <LinearGradientBrush EndPoint="0.493,0.002" StartPoint="0.493,0.33"> <GradientStop Color="#00E6D9AA" Offset="0.513"/> <GradientStop Color="#FFE6D9AA" Offset="0.996"/> </LinearGradientBrush> </Rectangle.Fill> </Rectangle> <Rectangle RadiusX="10" RadiusY="10" RenderTransformOrigin="0.493,0.485" StrokeThickness="10" Stroke="{x:Null}" Grid.RowSpan="2" Margin="1,1,1,1"> <Rectangle.Fill> <LinearGradientBrush EndPoint="0.99,0.441" StartPoint="0.794,0.441"> <GradientStop Color="#00E6D9AA" Offset="0.513"/> <GradientStop Color="#FFE6D9AA" Offset="0.996"/> </LinearGradientBrush> </Rectangle.Fill> </Rectangle> <TextBlock Text="TextBlock" TextWrapping="Wrap" x:Name="TextBlockToolTip" RenderTransformOrigin="0.5,0.5" Grid.Row="1" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="20,0,0,20" /> <TextBlock Name="ToolTipTitle" HorizontalAlignment="Stretch" Margin="15,16,15,6.1" FontSize="14" Text="title" d:LayoutOverrides="Height" /> </Grid> </UserControl> 同时。我们需要添加一些方法和属性来控制这些元素。 namespace CustomToolTip { public partial class UserControl1 : UserControl { public UserControl1() { InitializeComponent(); } public double UserControlToolTipX { get { return this.UserControlToolTipXY.X; } set { this.UserControlToolTipXY.X = value; } } public double UserControlToolTipY { get { return this.UserControlToolTipXY.Y; } set { this.UserControlToolTipXY.Y = value; } } public string UserControlTextBlockToolTip { get { return TextBlockToolTip.Text; } set { TextBlockToolTip.Text = value; } } public string UserControlToolTipTitle { get { return ToolTipTitle.Text; } set { ToolTipTitle.Text = value; } } } } ...

2012-10-14 · 3 min · bystander

WPF绘制圆角多边形

介绍 最近,我发现我需要个圆角多边形。而且是需要在运行时从用户界面来绘制。WPF有多边形。但是不支持圆角。我搜索了一下。也没找到可行的现成例子。于是就自己做吧。本文描述了圆角多边形的实现,也包括如何用在你的项目里。在Demo里面的RoundedCornersPolygon 类是完整的实现。 下载的Demo包括两部分 1. 通过XAML绘制圆角多边形 2. 运行时创建圆角多边形 背景 多边形可以被认为是沿着一个给定半径的圆的边缘和一些指定点/边。所构成的点的集合。 在WPF中。你可以给Polygon对象的Points属性添加一系列的点来制作多边形。 XAML方式 <Canvas> <Polygon Points="10,50 180,50 180,150 10,150" StrokeThickness="1" Stroke="Black" /> </Canvas> C#方式 var cnv = new Canvas(); var polygon = new Polygon {StrokeThickness = 1, Fill = Brushes.Black}; polygon.Points.Add(new Point(10, 50)); polygon.Points.Add(new Point(180, 50)); polygon.Points.Add(new Point(180, 150)); polygon.Points.Add(new Point(10, 150)); cnv.Children.Add(polygon); this.Content = cnv; 上面两个例子会输出下面的矩形 使用代码 我写的RoundedCornersPolygon 类和普通的多边形类很相似。但是有更多的属性来控制圆角。首先。看一个例子。展示一下圆角矩形类的使用 XAML方式 <Canvas> <CustomRoundedCornersPolygon:RoundedCornersPolygon Points="10,50 180,50 180,150 10,150" StrokeThickness="1" Stroke="Black" ArcRoundness="25" UseAnglePercentage="False" IsClosed="True"/> <Canvas> C#方式 var cnv = new Canvas(); var roundedPolygon = new RoundedCornersPolygon { Stroke = Brushes.Black, StrokeThickness = 1, ArcRoundness = 25, UseAnglePercentage = false, IsClosed = true }; roundedPolygon.Points.Add(new Point(10, 50)); roundedPolygon.Points.Add(new Point(180, 50)); roundedPolygon.Points.Add(new Point(180, 150)); roundedPolygon.Points.Add(new Point(10, 150)); cnv.Children.Add(roundedPolygon); this.Content = cnv; 输出如下: 多边形有四个主要属性 ArcRoundness 属性指定了从距离LineSegment终点多远的距离开始弯曲,通常和UseRoundnessPercentage 一起使用。UseRoundnessPercentage属性指定了ArcRoundness 值是百分比还是一个固定的值。 举个例子。ArcRoundness 被设置成10,而且UseRoundnessPercentage 被设置成false,那么弯曲将会在距离线段终点10的地方开始。而如果UseRoundnessPercentage 被设置成ture。则会是从线段终点10%的地方开始弯曲。 /// <summary> /// Gets or sets a value that specifies the arc roundness. /// </summary> public double ArcRoundness { get; set; } /// <summary> /// Gets or sets a value that specifies if the ArcRoundness property /// value will be used as a percentage of the connecting segment or not. /// </summary> public bool UseRoundnessPercentage { get; set; } IsClosed 指定多边形的最后一个点是否和第一个点闭合。为了成为一个多边形。一般应该被设置为true ...

2012-10-13 · 3 min · bystander

自定义WPF LinkLabel 控件

WPF里是没有LinkLabel控件的。因此我自己写一个。首先。我们看一下WPF中什么类似的组件可以实现这个链接功能 如果你想要模拟一个LinkLabel控件。你可以在TextBlock里使用内联的Hyperlink。像下面这样 <TextBlock> <Hyperlink> <Run Text="Test link"/> </Hyperlink> </TextBlock> 你可以使用Label控件。加一个内联的HyperLink,但是我认为TextBlock更好。因为你可以在Expression Blend 中通过InlineCollection 编辑所有子元素的属性 图1 虽然这种方法也行,但是我还是不太喜欢。因为我觉得我还是写一个类似windows窗体程序中的LinkLabel控件。然后我就做了。首先看一下控件的样子 图2 第一个是默认的LinkLabel控件。第二个是LinkLabelBehavior 属性被设置为HoverUnderline ,第三个的Foreground和 HoverForeground 属性都使用了自定的颜色。 LinkLabel控件支持的属性 1.Foreground和 HoverForeground属性 允许自定义这两个属性的值 2.LinkLabelBehavior 属性 允许设置下划线的显示与否 3.自定义HyperlinkStyle 属性 你可以使用这个属性给超链接设置自定义的样式。如果你已经自定了Foreground和 HoverForeground。则会被覆盖。 Url 超链接的目标 所有这些属性都继承自标准的System.Windows.Controls.Label 控件 通过Blend/Xaml设置这些属性很简单 <ThemedControlLibrary:LinkLabel Content="Link Label" FontSize="22"/> <ThemedControlLibrary:LinkLabel Content="Link Label" LinkLabelBehavour="HoverUnderline" /> <ThemedControlLibrary:LinkLabel Foreground="#FF847901" HoverForeground="#FF06C8F2" Content="Link Label" LinkLabelBehavour="NeverUnderline"/> 图三 然后是控件的使用方法。仅仅添加命名空间到xaml中。然后使用就行了。 <Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="DemoApplication.Window1" Title="DemoApplication" Height="300" Width="300" xmlns:ThemedControlsLibrary="clr-namespace:ThemedControlsLibrary;assembly=ThemedControlsLibrary" > <Grid> <ThemedControlsLibrary:LinkLabel HorizontalAlignment="Left" VerticalAlignment="Top" Content="LinkLabel"/> </Grid> </Window> 控件的完整代码很简单。就定义一下需要的属性,和控制这些属性应该显示在Blend中的(category)目录位置就行了。 public class LinkLabel : Label { private const string _linkLabel = "LinkLabel"; public static readonly DependencyProperty UrlProperty = DependencyProperty.Register("Url", typeof(Uri), typeof(LinkLabel)); [Category("Common Properties"), Bindable(true)] public Uri Url { get { return GetValue(UrlProperty) as Uri; } set { SetValue(UrlProperty, value); } } public static readonly DependencyProperty HyperlinkStyleProperty = DependencyProperty.Register("HyperlinkStyle", typeof(Style), typeof(LinkLabel)); public Style HyperlinkStyle { get { return GetValue(HyperlinkStyleProperty) as Style; } set { SetValue(HyperlinkStyleProperty, value); } } public static readonly DependencyProperty HoverForegroundProperty = DependencyProperty.Register("HoverForeground", typeof(Brush), typeof(LinkLabel)); [Category("Brushes"), Bindable(true)] public Brush HoverForeground { get { return GetValue(HoverForegroundProperty) as Brush; } set { SetValue(HoverForegroundProperty, value); } } public static readonly DependencyProperty LinkLabelBehavourProperty = DependencyProperty.Register("LinkLabelBehavour", typeof(LinkLabelBehaviour), typeof(LinkLabel)); [Category("Common Properties"), Bindable(true)] public LinkLabelBehaviour LinkLabelBehavour { get { return (LinkLabelBehaviour)GetValue(LinkLabelBehavourProperty); } set { SetValue(LinkLabelBehavourProperty, value); } } static LinkLabel() { FrameworkElement.DefaultStyleKeyProperty.OverrideMetadata( typeof(LinkLabel), new FrameworkPropertyMetadata(typeof(LinkLabel))); } } ...

2012-10-11 · 2 min · bystander

C#制作进度窗体

介绍 这是我在CodeProject上的第一篇文章。我希望对你有用 当我开发软件的时候。我通常因为一个很耗时是任务需要完成。而请求让用户等待,并且通过也允许用户取消。不论我做何种操作(比如下载文件。保存大文件等等)。我都需要做下面几件事: 通过一个模态对话框来让用户等待操作完成 能让用户看到进度。 能让用户随时取消。 我搜了好久也没找到拿来就能用的窗体控件,也许是我没找到。于是我自己写。。 图1 背景 BackgroundWorker 类包含了我需要完成任务的所有东西。我只需要给他提供一个对话框。 使用代码 ProgressForm 包含了一个BackgroundWorker ,你要做的仅仅就是提供了一个完成工作的方法。 ProgressForm form = new ProgressForm(); form.DoWork += new ProgressForm.DoWorkEventHandler(form_DoWork); //如果想为后台任务提供参数的话 form.Argument = something; 为了开始BackgroundWorker,只需要调用ShowDialog 方法。返回值则取决于任务是怎么完成的。 DialogResult result = form.ShowDialog(); if (result == DialogResult.Cancel) { //用户点击了取消 } else if (result == DialogResult.Abort) { /未处理的异常抛出 //你可以得到异常信息 MessageBox.Show(form.Result.Error.Message); } else if (result == DialogResult.OK) { //正常完成 //结果存储在 form.Result里 } 最后。任务方法看起来是这样的。 void form_DoWork(ProgressForm sender, DoWorkEventArgs e) { //得到参数 object myArgument = e.Argument; //做一些耗时的任务... for (int i = 0; i < 100; i++) { //通知进度 sender.SetProgress(i, "Step " + i.ToString() + " / 100..."); //... //检查是否点击了取消 if (sender.CancellationPending) { e.Cancel = true; return; } } } 如果你想要改改进度条,或者进度条显示的文本。SetProgress 有一些重载的方法 public void SetProgress(string status); public void SetProgress(int percent); public void SetProgress(int percent, string status); 最后一个可自定义的字符串是:有两个预定义的字符串CancellingText 和DefaultStatusText. CancellingText ,这两个字符串,当用户点击取消的时候显示 如何实现 ProgressForm 紧紧嵌入了一个BackgroundWorker ,并包装进了主函数。 首先。我设计了如图所示的一个窗体,然后。添加了BackgroundWorker。 public partial class ProgressForm : Form { public ProgressForm() { InitializeComponent(); worker = new BackgroundWorker(); worker.WorkerReportsProgress = true; worker.WorkerSupportsCancellation = true; worker.DoWork += new System.ComponentModel.DoWorkEventHandler(worker_DoWork); worker.ProgressChanged += new ProgressChangedEventHandler( worker_ProgressChanged); worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler( worker_RunWorkerCompleted); } void worker_DoWork(object sender, DoWorkEventArgs e) { } void worker_ProgressChanged(object sender, ProgressChangedEventArgs e) { } void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { } BackgroundWorker worker; } 我们必须把DoWork事件暴露给用户。我添加了一个委托。这样。我可以很容易的访问窗体成员 ...

2012-10-10 · 4 min · bystander

C#编写FTP客户端软件

1 介绍 我知道。网上有很多现成的FTP软件。但是。我们也想要了解FTP的一些底层机构,因此。 这个开源的项目在你学习FTP知识的时候也许对你有些帮组。程序的界面看起来像FileZilla,FileZilla虽然流行但是有些bug,当我打开我博客的时候总是有问题。我需要通过FTP连接我的服务器。发送文件,下载文件等等。因为。我决定写我自己的软件来处理所有的情况。FileZilla足够好。但它不是我的。 2 背景 看看我们已经知道的。我们知道FTP是一个标准的基于TCP网络协议。用于从一个主机向另一个主机传输文件。它是一个C/S架构。 图2 FTP程序曾经是基于命令行的。我们仍沿可以通过cmd.exe连接FTP服务器。因为FTP的确可以通过命令来操作。举个例子。我们可以在命令行使用“stor”命令来发送文件。为了完成这些请求。FTP服务器需要一直运行等待即将到来的客户端请求。我们可以从来自维基百科的解释更好的理解FTP: 客户端计算机可以通过服务器的21端口和服务器通信。叫做控制连接。它在一次会话期间保持开放。第一次连接的时候。叫做数据连接,服务器可以对客户端打开20端口(主动模式),建立一条数据通路,连接上客户端传输数据。或者客户端打开一个随机的端口(被动模式),去连接服务器,来传输数据。控制连接使用一个类似Telnet的协议,被用作客户端和服务器会话管理(命令,标识,密码)。。比如。“RETR filename” 会从服务器端下载文件。 图三 一个完整的FTP文件传输需要建立两种类型的连接,一种为文件传输下命令,称为控制连接,另一种实现真正的文件传输,称为数据连接。 服务器 通过三位ASCII的数字状态码,可能包含可选的描述信息,在控制连接上做出回应。比如。“200”或者是“200 OK”,表示上一条命令成功了。数字代表编号,描述信息给出了一些说明(比如“OK”),或者可能是一些需要的参数(比如需要帐号来存储文件),那么我们需要怎么做呢。很明显。发送命令,接收“OK”回应,发送数据。接收数据。完了。但是首先需要服务器已经准备好了。FTP服务器可以在主动和被动两种模式下运行。主动模式是基于服务器的连接而被动模式是基友客户端的连接。继续看。 在主动连接中,客户端把自己的ip和端口发送给服务器。然后服务器尝试连接到客户端,但是可能会因为防火墙的原因而被拒绝。我们在windows上都会使用反病毒/自带防火墙。是吧。那么我们来看看被动模式 在被动连接中。服务器通过一个“PASV”命令把自己的ip和端口发送给客户端。然后客户端通过该IP尝试连接服务器。对于发送文件非常有用。当我们发送文件的时候。优先使用“PASV”模式,如你们所说。大多数协议。像FTP/HTTP 使用ASCII编码,因为全球可用。因此我们会使用这种编码。你可以从下面得到FTP的命令列表 主动和被动都是对于服务器端来说的 3 使用代码 现在我们已经为编写软件做好准备了。我们写些有用的代码吧。:)首先。我们“打开文件对话框”,集成到我们的窗体里。 3.1 资源管理器组件 我们需要一个资源管理器组件在软件界面可以看到我们所有的文件。这样我们才可以选择哪些文件来发送到FTP服务器,新建一个Windows窗体控件库(下载包中提供了) 图四 最后看起来样子是上面这样。先添加一个TreeView,一些按钮,和一个搜索功能 TreeView.Nodes.Clear(); TreeNode nodeD = new TreeNode(); nodeD.Tag = Environment.GetFolderPath(Environment.SpecialFolder.Desktop); nodeD.Text = “Desktop”; nodeD.ImageIndex = 10; nodeD.SelectedImageIndex = 10; TreeView.Nodes.Add(nodeD); 就像上面代码展示的那样。我们需要添加地一个主节点。我的文档。我的电脑等等。然后获得子目录。 string[] dirList; dirList = Directory.GetDirectories(parentNode.Tag.ToString()); Array.Sort(dirList); if (dirList.Length == parentNode.Nodes.Count) return; for (int i = 0; i < dirList.Length; i++) { node = new TreeNode(); node.Tag = dirList[i]; node.Text = dirList[i].Substring(dirList[i].LastIndexOf(@"\") + 1); node.ImageIndex = 1; parentNode.Nodes.Add(node); } 可以从下载包里看到完整的代码。我们还应该处理鼠标单击事件。 现在我们有了一个资源管理器。还有FTP和VS所需要的所有信息。 首先,我们连接服务器。我们应该怎么做呢? FTPSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); AppendText(rchLog,"Status : Resolving IP Address\n",Color.Red); remoteAddress = Dns.GetHostEntry(Server).AddressList[0]; AppendText(rchLog, "Status : IP Address Found ->" + remoteAddress.ToString() + "\n", Color.Red); addrEndPoint = new IPEndPoint(remoteAddress, Port); AppendText(rchLog,"Status : EndPoint Found ->" + addrEndPoint.ToString() + "\n", Color.Red); FTPSocket.Connect(addrEndPoint); 是的。我们需要一个socket连接到服务器 ,然后发送命令 AppendText(rchLog, "Command : " + msg + "\n", Color.Blue); Byte[] CommandBytes = Encoding.ASCII.GetBytes((msg + "\r\n").ToCharArray()); FTPSocket.Send(CommandBytes, CommandBytes.Length, 0); //read Response ReadResponse(); ...

2012-10-09 · 2 min · bystander

理解并实现生成器模式

介绍 本文讨论生成器设计模式,讨论该模式什么情况下使用,怎么实现。并且。最后会有一个简单的生成器模式的实现。 背景 当我们的程序需要创建一个对象。而这个对象必须由很多不同的对象来构造的时候。为了构造最后的对象。我们不得不组合那些部分对象。最后我们会发现我们的代码被各种各样的部分对象的细节所弄的难以理解 为了说明上面的情况。我们做一个手机生产制造系统的例子。假定我们我们有一个已经安装在手机供应商那块的一个系统。现在供应商系那个要根据一些参数来创造一个新手机。比如触屏,操作系统,电池等。如果我们已经有了这些部分的对象,那么上述部分的任意组合将会导致客户端代码复杂难以管理。比如决定生产哪种手机的模块。 生成器模式目的就是解决上述问题的。GoF定义生成器模式如下: Separate the construction of a complex object from its representation so that the same construction process can create different representations. 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。 这个定义意味着我们不得不设计这个系统。通过一种客户端仅仅定义参数,而生成器则接管创建复杂对象 的方式。我们看一下生成器模式的类图。 然后看看上图中的每一个类都表示什么 ConcreteBuilder: 创建复杂产品的具体类.将会知道他已经创建的Product(产品),也就是他已经装配了的Product, 客户端通过该类得到Product对象. Builder: 创建Product的接口 Director: 客户端代码,定义了哪些部分应该被组合在一起来创建具体的Product Product: 这是通过组合很多部分创建的对象 使用代码 我们现在跟随上述的定义,然后试着去实现一个基本的生成器模式 我们先在合适的地方定义Product的不同部分,我们简单的定义一些枚举类型,那么我们就可以通过组合不同的部分创建Product了。 // 一些helper枚举定义各种零件 public enum ScreenType { ScreenType_TOUCH_CAPACITIVE, ScreenType_TOUCH_RESISTIVE, ScreenType_NON_TOUCH }; public enum Battery { MAH_1000, MAH_1500, MAH_2000 }; public enum OperatingSystem { ANDROID, WINDOWS_MOBILE, WINDOWS_PHONE, SYMBIAN }; public enum Stylus { YES, NO }; 然后,我们看一下Product类,我们需要有一个可以通过装配创建的Product类,这里我们定义一个MobilePhone类,也就是概念里的Product类了。 // 这是 "Product" 类 class MobilePhone { // 不同部分的字段 string phoneName; ScreenType phoneScreen; Battery phoneBattery; OperatingSystem phoneOS; Stylus phoneStylus; public MobilePhone(string name) { phoneName = name; } //公有属性访问这些部分 public string PhoneName { get { return phoneName; } } public ScreenType PhoneScreen { get { return phoneScreen; } set { phoneScreen = value; } } public Battery PhoneBattery { get { return phoneBattery; } set { phoneBattery = value; } } public OperatingSystem PhoneOS { get { return phoneOS; } set { phoneOS = value; } } public Stylus PhoneStylus { get { return phoneStylus; } set { phoneStylus = value; } } // 显示手机相关信息的方法 public override string ToString() { return string.Format("Name: {0}\nScreen: {1}\nBattery {2}\nOS: {3}\nStylus: {4}", PhoneName, PhoneScreen, PhoneBattery, PhoneOS, PhoneStylus); } } ...

2012-10-08 · 3 min · bystander

YAXLib---- XML序列化神器

今天早上翻译了Yet-Another-XML-Serialization-Library-for-the-NET,刚开始以为很短。翻译着发现不对。。然后你不逼你自己。怎么知道自己做不到。于是。将近4个小时把30页的文档翻译完了。因为文章很长。所以本文只列出前两部分。我把翻译好的做成了pdf, 文档下载:XML序列化神器 1 介绍 在本文中,会把要提到的XML序列化库叫做YAXLib,我们知道。.Net 还是提供了一些序列化功能的,尤其是XmlSerializer,该类被程序员广泛使用用来序列化对象成XML,当然,反序列化也是可以的。我认为XmlSerializer类的问题有几下几点 程序员不能自由的选择生成的xml的结构 不支持序列化一些集合类,比如Dictionary<,> 或者IEnumerable<>的属性 当反序列化的时候,如果缺失了一些域,则反序列化失败,这就使得用来存储一ixekeyi被用户编辑的配置文件变得不合适了。 2 为什么使用YAXLib YAXLib解决上述问题的特点 程序员可以决定xml文件的结构,一个属性可以是一个子元素,或者是其他属性的属性,或者是一个在类中没有对应属性的元素。 集合类也可以被序列化成一个逗号分隔(也可以是其他任何分隔符)的数据项列表,而且。为Dictionary<,>对象实现了一些特殊的格式化功能,这样,使得程序员可以完全控制生成的xml文件的结构 他支持System.Collections.Generic 命名空间中的所有泛型集合类(像Dictionary, HashSet, LinkedList, List, Queue,SortedDictionary, SortedList, 和 Stack) 和在System.Collections 命名空间中的非泛型集合类( ArrayList, BitArray, Hashtable, Queue, SortedList, 和 Stack)非泛型集合类可以包含多种不同的对象,而且,库还支持序列化和反序列化一维,多维,不规则的数组。 支持通过对基类/接口的引用,实现对一些对象集合的序列化和反序列化。 支持多级反序列化 程序员可以为生成的xml提供注释 当进行反序列化的时候,程序员可以选择性对于那些与类的属性相关,但没有出现在xml文件中的数据应该如何处理。这种情况下可以看错是一个错误,然后类库抛出一些异常,或者记录错误,或者可以被看成一个警告,然后用程序员预定义的值赋给对应的属性,而且,程序可以可以选择忽略这个问题,相关的异常将既不抛出也不作任何记录。请查看保留空引用标识那一节 看看什么时候可以忽略孤立的数据也许对你有帮助 程序员可以自己选择错误处理规则,对于数据敏感的应用程序,程序员可以选择在任何异常的情况下,库都应该抛出并且记录异常,对于其他的一些情况(比如要求不那么高的配置文件的存储),程序员可以选择把异常仅仅看成一个警告,仅仅记录一下,让程序的其他部分继续运行。 文档下载:XML序列化神器 著作权声明:本文由http://leaver.me 翻译,欢迎转载分享。请尊重作者劳动,转载时保留该声明和作者博客链接,谢谢!

2012-10-05 · 1 min · bystander

简单扩展方法增强代码可读性

本文技术含量不高,但是思路可以借鉴。。 介绍 当你处理计时器,时间间隔,或是其他关于日期的计算的时候。你必然会使用TimeSpan类。 我觉得写出下面的代码可读性并不好。。 // 1个表示5小时的时间间隔 var theTimespan = new TimeSpan(0, 5, 0, 0, 0); 而下面的代码就要好一些 //一个表示5小时的时间间隔 var theTimespan = 5.Hours(); ** 扩展方法** 使用这些扩展了int类的方法。可以使得创建TimeSpan可读性更好 public static TimeSpan Days(this int value) { return new TimeSpan(value, 0, 0, 0, 0); } public static TimeSpan Years(this int value) { var dt = DateTime.Now.AddYears(value); return (dt - DateTime.Now).Duration(); } public static TimeSpan Hours(this int value) { return new TimeSpan(0, value, 0, 0, 0); } public static TimeSpan Minutes(this int value) { return new TimeSpan(0, 0, value, 0, 0); } public static TimeSpan Seconds(this int value) { return new TimeSpan(0, 0, 0, value, 0); } public static TimeSpan Milliseconds(this int value) { return new TimeSpan(0, 0, 0, 0, value); } 许可 本文所有源代码包括文件在CPOL下授权。。 原文地址:Simple-extension-methods-for-code-readability 著作权声明:本文由http://leaver.me 翻译,欢迎转载分享。请尊重作者劳动,转载时保留该声明和作者博客链接,谢谢!

2012-10-04 · 1 min · bystander

11个高效的VS调试技巧

介绍 调试是软件开发周期中的一个很重要的部分,有时很有挑战性,有时候则让程序员迷惑,有时候让程序员发疯,但是。可以肯定的是,对于任何不是太那个微不足道的程序来说,调试是不可避免的。近年来,调试工具的发展已经使得很多调试任务简单省时了。 本文总结了十个调试技巧,当你使用VS的时候可以节省你很多时间。 1. 悬停鼠标查看表达式 调试有时候很有挑战性,当你步入一个函数想看看哪块出错的时候,查看调用栈来想想值是从哪来的。另一些情况下,则需要添加一些监视表达式,或者查看局部变量列表,这通常还是花费一些时间的,但是。如果你把你鼠标指向你感兴趣的一个变量。你会发现事情简单多了。而且,类和结构体可以通过单击展开。这样。你就可以方便快捷的找到你想查看的变量了。 2. 实时改变值 调试器不仅仅是一个分析程序崩溃或是异常结果的工具了,许多bug都可以通过步入新写的函数,检查函数是否如期望的那样运行来预防。有时候你可能会好奇“如果条件为真函数会正确运行吗”大多数情况下,根本不需要改变代码重启挑起,仅仅把鼠标悬停到一个变量上,双击值然后输入一个新值就可以了。。 3.设置下一条语句 一个典型的调试情况就是通过单步跟踪分析为什么一个函数调用失败了。当你发现一个函数调用的另一个函数返回错误的时候你会怎么做?重启调试?有更好的方法。拖动这个黄色的语句标识到你想下一步执行的语句前就可以了。比如你刚才失败的那块,然后步入。简单,不是吗? 4.编辑然后继续 调试一个复杂的程序,或是一个插件的时候,在一个被调用很多次的函数处发现一个错误。但是不想浪费时间停下来,重新编译然后重新调试。没问题,仅仅在该处改正代码然后继续单步就可以。VS会修正程序然后继续调试不需要重启 注意,编辑然后继续有大量的已知限制,首先,64位代码是不行的。如果他如果为你的C#程序工作。就去工程设置的生成选项,然后目标平台为x86.不要担心。发布版的目标平台和调试的时候是分开的。可以被设置为任何平台。。 第二.编辑然后继续改变在一个方法里应该是局部的。。如果你改变了方法签名,添加一些新方法或是类。你就不得不重启程序了。或者撤销改变来继续。改变方法也包含lambda表达式隐式修改的自动生成的代理类,因此也不能继续。 5.方便的监视窗口 大概现代的调试器都有一个监视窗口,无论如何。VS允许你简单的添加或移除变量。单击空行,输入你的表达式按下回车,或者是在不需要的表达式上按下Delete键就可以删除了。 而且。从监视窗口你不仅仅可以看到“正常”的变量。你可以输入$handles 来追踪你的程序打开了多少句柄(可以方便的修复内存泄漏) ,输入$err 可以看到上一个函数的错误码,然后使用工具-错误信息可以看到更详细的描述,或者输入@eax(64位是@rax)来查看包含函数返回值的寄存器。 6.带注释的反汇编 使用交互式的反汇编模式可以使得优化程序的关键部分变得很容易,VS给出对应你代码每一行的汇编指令,并且运行单步运行。同时,可以在任何位置设置断点。而且,表达式的查看和修改也像在C++代码里一样 7.带有栈的线程窗口 调试多线程的程序是痛苦的。。或者也可以是很有趣的。取决于你的调试器。VS2010真正优美的特性是线程窗口的栈视图,通过窗口的调用栈你可以方便的总览线程。 8.条件断点 如果你尝试通过断点再现一个罕见的事件,该情况引发了一些严重的错误。你可以添加条件断点。定义一个断点的条件,然后如果条件不成立,VS会忽略该断点 9.内存窗口 有些bug由不正确的结构体定义引起,忽略的对齐属性等等。查看内存中的内容可以定位然后修复bug。VS提供了一个放百年的内存窗口,可以把值以8/16/32/64位的形式展示。还有浮点值。也允许实时改变他们。就像在文本编辑器里一样。 10.转到定义 这个特性不是直接关于调试的,而是关于浏览大项目的。如果你尝试找到一些不是你自己写的代码中的错误,快速知道“这个类型是什么”或者“这个函数是干嘛的”,可以节省很多时间,VS通过一个转到定义命令方便了你。 11.命令窗口 第十一的技巧chaau已经建议过了。确实可以节省很多时间,VS支持命令窗口,可以通过,视图-其他窗口-命令窗口来启动。一旦激活,你可以输入不同的命令来自动化调试。举个例子。你可以通过如下命令 简单的模拟MFC COleDateTime 变量。 ? dt.Format("%Y-%m-%d %H:%M:%S") 许可 本文包括源代码和文件在CPOL下授权。 原文地址:10plus-powerful-debugging-tricks-with-Visual-Studi 著作权声明:本文由http://leaver.me 翻译,欢迎转载分享。请尊重作者劳动,转载时保留该声明和作者博客链接,谢谢!

2012-10-03 · 1 min · bystander