日志标签:C#

如果你想学好编程!就一定要看这个!对无论有多厉害的你有很多帮助!

时间:2014年03月06日作者:小侃评论次数:0

此处仅以C#为例,其他编程语言也同样适用。

把C#当成一门新的语言学习;  
.看《C#入门经典》和《C#高级编程》;  
.不要被VC、BCB、BC、MC、TC等词汇所迷惑——他们都是集成开发环境,而我们要学的是一门语言;  
.不要放过任何一个看上去很简单的小编程问题——他们往往并不那么简单,或者可以引伸出很多知识点  
.会用Visual vs,并不说明你会C#;  
.学c#并不难,长期坚持实践和不遗余力的博览群书;  
.如果不是天才的话,想学编程就不要想玩游戏! 
.看Visual vs的书,是学不了C#语言的;  
.浮躁的人容易说:XX语言不行了,应该学YY;——是你自己不行了吧!?  
.浮躁的人容易问:我到底该学什么;——别问,学就对了;  
.浮躁的人容易问:XX有钱途吗;——建议你去抢银行;  
.浮躁的人容易问:XX和YY哪个好;——告诉你吧,都好——只要你学就行;  
.浮躁的人分两种:a)只观望而不学的人;b)只学而不坚持的人;  
.把时髦的技术挂在嘴边,还不如把过时的技术记在心里;  
.C#不仅仅是支持面向对象的程序设计语言;  
.学习编程最好的方法之一就是阅读源代码;  
.在任何时刻都不要认为自己手中的书已经足够了;  
.看得懂的书,请仔细看;看不懂的书,请硬着头皮看;  
.别指望看第一遍书就能记住和掌握什么——请看第二遍、第三遍;  
.和别人一起讨论有意义的C#知识点,而不是争吵XX行不行或者YY与ZZ哪个好;  
.请不要认为学过XX语言再改学C#会有什么问题——你只不过又在学一门全新的语言而已;  
.读完了《C#高级编程》以后再来认定自己是不是已经对C#入门了;  
.学习编程的秘诀是:编程,编程,再编程;  
.记住:面向对象技术不只是C#专有的;  
.请把书上的程序例子亲手输入到电脑上实践,即使配套光盘中有源代码;  
.把在书中看到的有意义的例子扩充;  
.请重视C#中的异常处理技术,并将其切实的运用到自己的程序中;  
.经常回顾自己以前写过的程序,并尝试重写,把自己学到的新知识运用进去;  
.不要漏掉书中任何一个练习题——请全部做完并记录下解题思路;  
.C#语言和C#的集成开发环境要同时学习和掌握;  
.既然决定了学C#,就请坚持学下去,因为学习程序设计语言的目的是掌握程序设计技术,而程序设计技术是跨语言的;  
.就让C#语言的各种平台和开发环境去激烈的竞争吧,我们要以学习C#语言本身为主;  
.当你写C#程序写到一半却发现自己用的方法很拙劣时,请不要马上停手;请尽快将余下的部分粗略的完成以保证这个设计的完整性,然后分析 

自己的错误并重新设计和编写;  
.决不要因为程序“很小”就不遵循某些你不熟练的规则——好习惯是培养出来的,而不是一次记住的;  
.每学到一个C#难点的时候,尝试着对别人讲解这个知识点并让他理解——你能讲清楚才说明你真的理解了;  
.记录下在和别人交流时发现的自己忽视或不理解的知识点;  
.请不断的对自己写的程序提出更高的要求,哪怕你的程序版本号会变成XX;  
.保存好你写过的所有的程序——那是你最好的积累之一;  
.请不要做浮躁的人;  
.请热爱C#! 

深入解析和破解C#的readonly只读字段及与const的区别

时间:2014年02月28日作者:小侃评论次数:0

 

 

 

 

返回目录

请允许我再唠叨几句const和readonly

readonly 关键字与 const 关键字不同。 const 字段只能在该字段的声明中初始化。 readonly 字段可以在声明或构造函数中初始化。 因此,根据所使用的构造函数,readonly 字段可能具有不同的值。 另外,const 字段为编译时常数,而 readonly 字段可用于运行时常数。

其实大家都懂的,我就不多废话,直接重点:

Const:
1>必须在定义时就进行赋值,并且赋值为常量,不能赋值为变量。
2>const常量隐含是static的,所以只能用类名来进行方法.
3>常量的类型可以为简单类型,枚举类型,各种引用类型(包括string)。这里引用类型的常量,如果不是string类型,则只允许赋以null。常量的类型不能为普通的struct类型。如果要实现struct类型的保持不变的量,可以用readonly。
4>const可以修饰方法内的局部变量。
 
ReadOnly:
1>readonly域可以是各种类型。
2>readonly域可以用变量或表达式进行赋值
3>readonly不能修饰局部变量。
4>readonly域并不隐含static性质。
5>readonly域要求定义时初始化。如果没有初始化,自动取默认值(0,false,null等)。如果要赋值,可以定义时初始化,也可以在构造方法中赋值,包括使用out及ref参数进行处理。但它最多只能被赋值一次。赋值以后,其值不能被修改。
 
可以看出,readonly要求的只读性时考虑”运行时时只读的”,而const要求的只读性是”编译时就是常量”。

 

好了,下面开始修改readonly字段。

 

 

返回目录

计策1:反间计 —— 反射修改

要说什么方法不用我们另外做手脚直接了当快速轻松得修改readonly只读属性莫过于使用.NET中的正规方式,当你直接对readonly字段进行“=”赋值操作然后编译,VS肯定给你个错误拒绝编译。但是另一种动态赋值方式——反射你有没有试过呢???

 

好吧或许你曾经问过某高手说readonly字段能不能被修改,他一定会回答:“笨蛋,这还用问,能修改还叫readonly吗?”。于是聪明人知道了并记住了(或许聪明人根本不会问这样的问题)。但是……一个笨的很笨的小笨他太笨了所以还是想试试,于是先用第一种直接静态赋值方式,VS编译错误。又尝试另一种运行后的动态赋值,于是他成功了!

 

是的,静态方式编译器不允许,但是动态赋值——反射却背叛了它,运行后用反射想怎么改就怎么改!

看下面代码:

class Program

{

static readonly object data = 1;

 

static void Main()

{

Console.WriteLine(data);

mod();

Console.WriteLine(data);

}

 

static void mod()

{

//得到静态的非公有字段信息

var fieldInfo = typeof(Program).GetField(“data”, BindingFlags.Static | BindingFlags.NonPublic);

fieldInfo.SetValue(null, “MOD”);

}

}

 

 

输出:

1

MOD

 

值被成功修改了。

 

 

返回目录

计策2:借刀杀人——调节字段偏移位置的结构体来修改

如果你经常用C#调用非托管代码的话,P/Invoke和各种Marshal操作你会很熟悉。而另一个常用到的System.Runtime.InteropServices的StructLayout和FieldOffset特性是用来定义一个显示的字段内存布局的结构体。

 

没人可以阻止我们把两个字段对在一个位置,然后用一个非readonly字段去彻底控制一个readonly字段!!!

 

代码

using System;

using System.Runtime.InteropServices;

 

namespace Mgen.TTC

{

[StructLayout(LayoutKind.Explicit)]

struct a

{

[FieldOffset(0)]

public string s;

[FieldOffset(0)]

public readonly string READ_ONLY;

//readonly字段

 

public a(string arg)

{

//初始化readonly字段

s = READ_ONLY = arg;

}

}

 

class Program

{

static void Main()

{

//此时oa的readonly字段被初始化成字符串:”常量”

a oa = new a(“常量”);

 

Console.WriteLine(oa.READ_ONLY);

oa.s = “你被改了……”;

Console.WriteLine(oa.READ_ONLY);

}

}

}

输出:

常量

你被改了……

 

很好,这里修改变量s就等价于修改常量字段:READ_ONLY。两个字段是对在同一个内存位置的,然后通过修改一个非readonly字段去间接修改一个readonly字段。

 

 

 

 

返回目录

计策3:无中生有——使用ilasm创建强行修改语句

当你使用Visual Studio(或其他C#编译器)时对readonly字段进行赋值肯定结果是编译错误。于是你很想强行通过这条语句(于是你又非常使劲得按了下Ctrl + F5,结果……),好吧C#编译器都一个样,无法去改变它,但是C#幕后的IL并非如此。接下来让我们用ilasm.exe创建一个对readonly字段进行直接赋值的程序。

ilasm的编译需要一个IL文件,这个IL文件就是文本文件,你可以自己写IL,不过这个太麻烦了,我们可以用IL反编译程序ildasm.exe来把一个托管程序集的IL代码框架先生成,然后导出,最后加入自己的代码再用ilasm编译。

 

首先创建一个C#控制台程序,然后加一个readonly只读字段,编译(这样做我们就不用从头开始写IL)。如下:

class Program

{

static readonly string s = “hehe”;

static void Main(string[] args)

{ }

}

接着用ildasm.exe打开这个程序。

(ildasm在Windows SDK中,Windows SDK路径在:%PROGRAMFILES%\Microsoft SDKs\Windows)

 

在File菜单选择Dump(或直接按Ctrl+D)。选择OK将IL文件保存。

 

然后用文本编辑器打开这个IL文件,找到Main函数(可以通过查找文字:Main)。在主函数.entrypoint指令下加入下列指令:

代表4条C#语句:输出s,修改s,再输出s,Console.Read()。

(注意下面的ConsoleApplication1.Program::s代表s字段的完整命名空间,根据你的程序做适当修改)

.maxstack  8

IL_0000:  ldsfld     string ConsoleApplication1.Program::s              //s进栈

IL_0005:  call       void [mscorlib]System.Console::WriteLine(string)   //输出s

IL_000a:  ldstr      bytearray (AB 88 EE 4F 39 65 )                     //字符串被修改”

IL_000f:  stsfld     string ConsoleApplication1.Program::s              //将”被修改”赋值给s

IL_0014:  ldsfld     string ConsoleApplication1.Program::s              //s进栈

IL_0019:  call       void [mscorlib]System.Console::WriteLine(string)   //输出s

IL_001e:  call       int32 [mscorlib]System.Console::Read()             //Console.Read()

IL_0023:  pop

IL_0024:  ret

 

接下来就用ilasm.exe来编译IL文件。

(ilasm在.NET Framework安装目录下,路径:%SYSTEMROOT%\microsoft.net\framework\)

 

将刚才修改后的IL文件路径作为第一个参数传入ilasm.exe中,ilasm便会将IL编译成可执行文件。然后运行这个exe。

 

程序会输出:

hehe

被修改

 

你可以在Reflector(或ILSpy)中打开这个程序,它的C#代码正好是C#编译器所不允许编译的结果:

internal class Program

{

// Fields

private static readonly string s = “hehe”;

 

// Methods

private static void Main(string[] args)

{

Console.WriteLine(s);

s = “被修改”;

Console.WriteLine(s);

Console.Read();

}

}

 

 

 

 

返回目录

为什么?——翻阅CLI标准:initonly修饰符

 

注意:

下文会引用Common Language Infrastructure (CLI) 标准的内容,如果你想亲自看一下CLI标准的内容。可以在这里下载:http://www.ecma-international.org/publications/standards/Ecma-335.htm

 

 

看完了上面的东西,你一定会问为什么?为什么执行环境没有去有效得保护一个readonly字段?为什么IL允许去修改一个readonly字段而C#不可以?

 

让我们开始分析一个readonly字段。如下C#代码:

readonly int i;

 

接下来,你应该猜到了,又开始IL了……

(汗……别抱怨怎么又得从IL上说起,我也不想这样做,其实IL也挺无奈的,人家很低调的,但总被一些人给不停得揭露出来……仿佛他们研究得很深奥似的……(我在自嘲,没说别人))

 

上面代码会被编译成下面的IL:

.field private initonly int32 i

 

可以看出来,readonly字段就是一个带有initonly的字段,一切的不同就在这个initonly修饰符上。

 

根据CLI标准(ECMA-334),第二部分:元数据(Partition II Metadata),16. 定义和引用字段(16 Defining and referencing fields),1. 字段的属性(Attributes of field),2. 字段约定属性(Field contract attributes)中对initonly修饰符的描述

initonly marks fields which are constant after they are initialized. These fields shall only be mutated inside a constructor. If the field is a static field, then it shall be mutated only inside the type initializer of the type in which it was declared. If it is an instance field, then it shall be mutated only in one of the instance constructors of the type in which it was defined. It shall not be mutated in any other method or in any other constructor, including constructors of derived classes.

[Note: The use of ldflda or ldsflda on an initonly field makes code unverifiable.  In unverifiable code, the VES need not check whether initonly fields are mutated outside the constructors. The VES need not report any errors if a method changes the value of a constant. However, such code is not valid. end note]

上面第一段就是在说readonly的用法:initonly字段在初始化后就成为常量。这种字段只能在构造函数中改变(进行赋值)。如果是静态字段,只能在当前类静态构造函数中或初始设定项。如果是非静态字段,只能在当前类的非静态构造函数中使用(或类型初始设定项),不能在其他方法或者其他构造函数中,包括派生类的构造函数。

 

第二段找到了重点(以Note开始)。对initonly字段使用ldflda和ldsflda会使代码无法验证。在无法通过验证的代码环境中,VES不需要检查initonly字段是否在构造函数外发生改变,VES也不需要报错如果一个方法改变了这个只读字段的值。但是,这种代码不是合法的。

 

其中VES(Virtual Execution System):虚拟执行系统是指代码的运行环境,而微软的CLI执行就是CLR。

 

IL指令:ldflda(ldsflda用于静态字段)用于将字段的地址进栈。当使用ref/out关键字时,或者调用值类型的成员时,CLR都会把相应对象的地址压入栈中。(其实上面提到ldflda/ldsflda是指去修改readonly字段,所以不一定只限于ldflda/ldsflda,当然也没准其他IL指令会间接用到ldflda/ldsflda)

 

OK,那么其实CLI标准没有强制要求执行环境必须要确保readonly只读字段必须遵守行为准则,只要readonly字段被非法修改,代码将会无法验证(unverifiable)。下面的问题就是无法验证的代码又是一个什么概念?

 

 

 

返回目录

捕获MSIL的代码验证错误

当MSIL被JIT编译时,如果程序集没有被赋予跳过代码验证的权限时,那么代码必须要通过代码验证过程,代码验证直接确保了程序的类型安全,使得对象可以绝对隔离并且免受恶意破坏,代码验证所要做的是如下具体3点:

  • 对类型的引用与被引用的类型严格兼容。
  • 在对象上只调用正确定义的操作。
  • 标识与声称的要求一致。

(强烈建议阅读MSDN – 托管执行过程 – 将 MSIL 编译为本机代码 – 代码验证(http://msdn.microsoft.com/zh-cn/library/k5532s8a.aspx))

 

上面提到的“跳过代码验证的权限”就是SecurityPermissionFlag.SkipVerification枚举值,而本机运行的.NET程序集默认是被给予全部权限的,因此会包含这个权限。IL代码验证是不发生的。接下来要做的就是通过创建一个没有“跳过代码验证的”应用程序域,在这个应用程序域中运行上面用IL创建的那个修改只读字段的程序集,看看会发生什么情况。

 

创建另一个控制台应用程序(最好把刚才的IL编译的修改只读字段的程序拷贝到此程序的编译目录下,这样可以用相对路径),然后创建一个应用程序域,并执行刚才的程序集:

static void Main()

{

//创建一个没有跳过代码验证权限的应用程序域

var appdomain = CreateSandbox();

//testApp.exe是刚才用IL编译的修改readonly只读字段的程序的路径

appdomain.ExecuteAssembly(“testApp.exe”);

}

 

static AppDomain CreateSandbox()

{

//初始化空的权限集

var pset = new PermissionSet(PermissionState.None);

//添加Execution(执行)安全权限,没有此权限代码不会执行

pset.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));

//添加其他权限

pset.AddPermission(new FileIOPermission(PermissionState.Unrestricted));

pset.AddPermission(new UIPermission(PermissionState.Unrestricted));

 

 

//必须设置AppDomainSetup.ApplicationBase,否则无法成功创建应用程序域

var adSetup = new AppDomainSetup();

adSetup.ApplicationBase = AppDomain.CurrentDomain.SetupInformation.ApplicationBase;

 

var domain = AppDomain.CreateDomain(“新的AppDomain”,

null,

adSetup,

pset);

 

return domain;

}

 

 

运行结果:有异常抛出。很好,这正是我们想要的结果:

Unhandled Exception: System.Security.VerificationException: Operation could dest

abilize the runtime.

at ConsoleApplication1()      //用IL编译的程序的主函数

at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args

)

at System.AppDomain.ExecuteAssembly(String assemblyFile, String[] args)

at System.AppDomain.ExecuteAssembly(String assemblyFile)

at System.AppDomain.ExecuteAssembly(String assemblyFile)

at Mgen.TTC.Program.Main()    //当前程序的主函数

可以看到System.Security.VerificationException异常被抛出。”operation could destabilize the runtime”:指操作可能使运行时刻不稳定。因为这个用IL编译的程序集包含上面提到过的“无法验证”的代码,而当前执行的应用程序域又没有被给予“跳过代码验证的安全权限”,因此代码验证此刻会发生,当程序集运行时,JIT边编译边进行代码验证,而觉察到这个“修改只读属性”的语句,它打破了代码验证所强制的运行时刻类型安全,显然破坏了运行时刻稳定性,接着马上抛出VerificationException异常,程序集执行失败。

 

 

如果你把上面的应用程序域的限制权限改成全部权限:

var pset = new PermissionSet(PermissionState.Unrestricted);

重新运行一下程序,这次没有任何异常抛出,另一个程序集的只读字段会继续被修改并输出正确结果。

hehe

被修改

 

 

 

 

返回目录

总结

如果你仔细看了文章,那么“总结”对你来意义不大,因为你肯定已经自己理解了。当然如果你没时间全看完,总结告诉你的是(请从上往下看):

  • readonly对象本质上不是常量,是字段。
  • 标准(CLI标准)没有规定readonly字段不能被修改。
  • 因为标准不强求,更何况readonly对象是字段,所以IL和反射都可以修改它。
  • 当然编译器还是要尽量阻止它被修改(如果编译器都允许它被修改,那readonly这个关键字还有什么用?)
  • 一旦readonly字段被修改了,该代码就属于无法验证代码。
  • MSIL在被JIT编译时会验证代码,如果遇到无法验证代码会抛出异常。
  • 当然有专门的权限可以使程序代码跳过(可以理解成不进行)代码验证。
  • 默认情况下本机程序拥有所有权限,所以修改readonly字段没有异常。当在部分信任的环境下程序集可以收到System.Security.VerificationException代表代码验证异常。

 

C#高级编程:Invalidate()方法学习

时间:2014年02月21日作者:小侃评论次数:0

Invalidate()是System.Windows.Forms.Form的一个成员,它把客户窗口区域标记为无效,因此在需要重新绘制时,它可以确保引发Paint事件。Invalidate()有两个重载方法:可以给它传送一个矩形,指定(使用页面坐标)需要重新绘制哪个窗口区域,如果不提供任何参数,它就把整个客户区域标记为无效。

为什么要这么做如果知道需要绘制某些内容,为什么不调用OnPaint()或直接完成绘制任务的其他方法一般情况下,最好不要直接调用绘图例程,如果代码要完成某些绘图任务,此时一般应调用Invalidate()。其原因如下所示:

 

● 绘图总是GDI+应用程序可以执行的一种处理器密集型的任务。在其他工作的中间进行绘图会妨碍其他工作的进行。在前面的示例中,如果在LoadFile()方法中直接调用一个方法来完成绘图,LoadFile()方法就将在绘图工作完成后才能返回。在这段时间里,应用程序不会响应其他事件。另一方面,通过调用Invalidate(),在从LoadFile返回之前,就可以让Windows引发一个Paint事件。接着Windows就可以检查等待处理的事件了。其内部的工作方式是事件被当作消息队列中一个消息。Windows会定期检查该队列,如果其中有事件,Windows就选择它,并调用相应的事件处理程序。现在Paint事件是队列中的惟一事件,所以OnPaint()会被立即调用。但是,在一个比较复杂的应用程序中,可能会有其他事件,其中一些的优先权比OnPaint()高。特别是如果用户已决定退出应用程序,该事件就会用消息WM_QUIT来标记。

● 与第一个原因相关,如果有一个比较复杂的多线程应用程序,就会希望用一个线程处理所有的绘图操作。使用Invalidate()可以把所有的绘图操作传递到信息队列中,这有助于确保无论其他线程请求什么绘图操作,都由同一个线程完成所有的绘图操作(无论什么线程负责信息队列,都是由线程Application.Run()处理绘图操作)。

● 还有一个与性能有关的原因。假定在某一时刻有几个不同的屏幕绘制请求,也许代码仅能修改文档,以确保显示更新的文档,而同时用户刚刚移开另一个覆盖部分客户区域的窗口。调用Invalidate(),可以让Windows注意到发生的事件。Windows就会在需要时合并Paint事件,合并无效的区域,这样绘图操作就只执行一次。

● 最后,执行绘图的代码可能是应用程序中最复杂的代码部分,特别是当有一个比较专业化的用户界面时,就更是如此。需要长时间维护该代码的人员希望我们把所有的绘图代码都放在一个地方,且尽可能简单—— 如果程序的其他部分没有过多的路径进入该代码部分,维护就更容易。

其底线是最好把所有的绘图代码都放在OnPaint()例程中,或者在该方法中调用的其他方法中。但是要维持一个平衡。如果要在屏幕上替换一个字符,最好不要影响到已经绘制好的其他内容,此时可能不需要使用Invalidate(),而只需编写一个独立的绘图例程。

注意:

在非常复杂的应用程序中,甚至可以编写一个完整的类,专门负责在屏幕上绘图。几年前MFC仍是GDI密集型应用程序的标准技术,MFC就遵循这个模式,使用一个C++类CView完成绘图操作。但即使是这样,这个类也有一个成员函数OnDraw(),用作大多数绘图请求的入口点。

转自:http://www.tzwhx.com/newOperate/html/1/12/124/10475.html

C#中Invalidate() 方法

 

重载列表

使控件的特定区域无效并向控件发送绘制消息。

 

受 .NET Framework 精简版的支持。

 

[C#] public void Invalidate();[C++] public: void Invalidate();使控件的特定区域无效并向控件发送绘制消息。还可以使分配给该控件的子控件无效。

 

[C#] public void Invalidate(bool);使控件的指定区域无效(将其添加到控件的更新区域,下次绘制操作时将重新绘制更新区域),并向控件发送绘制消息。

 

受 .NET Framework 精简版的支持。

 

[C#] public void Invalidate(Rectangle);使控件的指定区域无效(将其添加到控件的更新区域,下次绘制操作时将重新绘制更新区域),并向控件发送绘制消息。

 

[C#] public void Invalidate(Region);使控件的指定区域无效(将其添加到控件的更新区域,下次绘制操作时将重新绘制更新区域),并向控件发送绘制消息。还可以使分配给该控件的子控件无效。

 

[C#] public void Invalidate(Rectangle, bool);使控件的指定区域无效(将其添加到控件的更新区域,下次绘制操作时将重新绘制更新区域),并向控件发送绘制消息。还可以使分配给该控件的子控件无效。

 

[C#] public void Invalidate(Region, bool);示例

[Visual Basic, C#, C++] 下面的示例使用户能够将图像或图像文件拖到窗体上,并使它在放置点显示。每次绘制窗体时,都重写 OnPaint 方法以重新绘制图像;否则图像将保持到下一次重新绘制。DragEnter 事件处理方法决定拖到窗体中的数据的类型,并提供适当的反馈。如果 Image 可以从该数据中创建,则 DragDrop 事件处理方法就会在该窗体上显示此图像。因为 DragEventArgs.X 和 DragEventArgs.Y 值为屏幕坐标,所以示例使用 PointToClient 方法将它们转换成工作区坐标。

C#结构体类型基础详解

时间:2014年02月21日作者:小侃评论次数:0

结构是使用 struct 关键字定义的,与类相似,都表示可以包含数据成员和函数成员的数据结构。
一般情况下,我们很少使用结构,而且很多人也并不建议使用结构,但作为.NET Framework 一般型別系统中的一个基本架构,还是有必要了解一下的。
结构的特征:
结构是一种值类型,并且不需要堆分配。
结构的实例化可以不使用 new 运算符。
在结构声明中,除非字段被声明为 const 或 static,否则无法初始化。
结构类型永远不是抽象的,并且始终是隐式密封的,因此在结构声明中不允许使用abstract和sealed修饰符。
结构不能声明默认构造函数(没有参数的构造函数)或析构函数,但可以声明带参数的构造函数。
结构可以实现接口,但不能从另一个结构或类继承,而且不能作为一个类的基类,所有结构都直接继承自 System.ValueType,后者继承自 System.Object。
结构在赋值时进行复制。 将结构赋值给新变量时,将复制所有数据,并且对新副本所做的任何修改不会更改原始副本的数据。 在使用值类型的集合(如 Dictionary<string, myStruct>)时,请务必记住这一点。
结构类型的变量直接包含了该结构的数据,而类类型的变量所包含的只是对相应数据的一个引用(被引用的数据称为“对象”)。但是结构仍可以通过ref和out参数引用方式传递给函数成员。
结构可用作可以为 null 的类型,因而可向其赋 null 值。

struct A
    {
        public int x;           //不能直接对其进行赋值
        public int y;
        public static string str = null;   //静态变量可以初始化
        public A(int x,int y)   //带参数的构造函数
        {
            this.x = x;
            this.y = y;
            Console.WriteLine("x={0},y={1},str={2}", x, y,str);
        }

    }
    class Program
    {
        static void Main(string[] args)
        {
            A a =new A(1,2);
            A a1 = a;
            a.x =10;
            Console.WriteLine("a1.x={0}",a1.x);
            Console.Read();
        }
    }

结果为:x=1,y=2,str=
a1.x=1
此时a1.x值为1是因为,将a赋值给a1是对值进行复制,因此,a1不会受到a.x赋值得改变而改变。
但如果A是类,这时a和a1里的x引用的是同一个地址,则a1.x的值会输出10。
结构的装箱与拆箱
我们知道,一个类类型的值可以转换为object类型或由该类实现的接口类型,这只需在编译时把对应的引用当作另一个类型处理即可。
与此类似,一个object 类型的值或者接口类型的值也可以被转换回类类型而不必更改相应的引用。当然,在这种情况下,需要进行运行时类型检查。
由于结构不是引用类型,上述操作对结构类型是以不同的方式实现的。
当结构类型的值被转换为object 类型或由该结构实现的接口类型时,就会执行一次装箱操作。
反之,当 object 类型的值或接口类型的值被转换回结构类型时,会执行一次拆箱操作。
与对类类型进行的相同操作相比,主要区别在于:
装箱操作会把相关的结构值复制为已被装箱的实例,而拆箱则会从已被装箱的实例中复制出一个结构值。
因此,在装箱或拆箱操作后,对“箱”外的结构进行的更改不会影响已被装箱的结构。

struct Program
    {
        static void Main(string[] args)
        {
            int i =1;
            object o = i;    //隐式装箱
            i =123;
            Console.WriteLine("i={0},o={1}",i,o);
            Console.Read();
        }
    }
//结果为:i=123,o=1

结构与构造函数
我们知道结构不能使用默认的构造函数,只能使用带参数的构造函数,当定义带参数的构造函数时,一定要完成结构所有字段的初始化,如果没有完成所有字段的初始化,编译时会发生错误­。
结构可以使用静态构造函数吗?
可以,结构的静态构造函数与类的静态构造函数所遵循的规则大体相同。
结构的静态构造函数何时将触发呢?
结构的实例成员被引用,结构的静态成员被引用,结构显示声明的构造函数被调用。
但是创建结构类型的默认值不会触发静态构造函数。
为什么结构不能自定义无参数的构造函数?
结构类型的构造函数与类的构造函数类似,用来初始化结构的成员变量,但是struct不能包含显式默认构造函数,
因为编译器将自动提供一个构造函数,此构造函数将结构中的每个字段初始化为默认值表中显示的默认值。
然而,只有当结构用new实例化时,才会调用此默认构造函数。对值类型调用默认构造函数不是必需的。

    struct A
    {
        static A()
        {
            Console.WriteLine("I am A.");
        }
        public void Fun()
        {

        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            A a=new A();
            a.Fun();      //结构的实例成员被引用
            Console.Read();
        }
    }
结果为:I am A.

结构与继承:
一个结构声明可以指定实现的接口列表,但是不能指定基类。
由于结构不支持类与结构的继承,所以结构成员的声明可访问性不能是protected或protected internal。
结构中的函数成员不能是 abstract或 virtual,因而 override修饰符只适用于重写从System.ValueType继承的方法。
为在设计编程语言时将结构设计成无继承性?­
其实类的继承是有相当的成本的 ——由于继承性,每个类需要用额外的数据空间来存储“继承图”来表示类的传承历史,
通俗地说来就是我们人类的家族家谱,里面存储着我们的祖宗十八代,只有这样我们才知道我们从哪里来的,而家谱肯定是需要额外的空间来存放的。
大家不要觉得这个存放“继承图”的空间很小,如果我们的程序需要用10000个点(Point)来存放游戏中的人物形体数据的话,
在一个场景中又有N个人,这个内存开销可不是小数目了。所以我们可以通过将点(Point)申明成 Struct而不是class来节约内存空间。

interface ITest
    {
        void Fun(int x,int y);
    }
    struct A:ITest
    {
        public void Fun(int x,int y)    //隐式实现接口里的方法
        {
            Console.WriteLine("x={0},y={1}", x, y);
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            A a;                        //结构的实例化可以不使用new
            a.Fun(1, 2);
            Console.Read();
        }
    }
// 结果为:x=1,y=2

什么情况下结构的实例化可以不使用new?

当结构中没有参数时,结构的实例化可以不使用new;

当结构中有参数时,必须对结构中所有参数进行初始化后,才能不使用new对结构进行实例化。

什么时候使用结构?

结构体适合一些小型数据结构,这些数据结构包含的数据以创建结构后不修改的数据为主;

例如:struct类型适于表示Point、Rectangle和Color等轻量对象。

尽管可以将一个点表示为类,但在某些情况下,使用结构更有效。

如果声明一个10000个Point对象组成的数组,为了引用每个对象,则需分配更多内存;这种情况下,使用结构可以节约资源。­

定义的时候不会用到面向对象的一些特性;

结构体在不发生装箱拆箱的情况下性能比类类型是高很多的.

.net中字符串的常用方法

时间:2014年02月17日作者:小侃评论次数:0

字符串重要的一些属性:
1Length:获得字符串中字符的个数。
举例如下:
01.<FONTface=微软雅黑>string str = “hello”;
02.Console.WriteLine(str.Length);
03.//输出结果为:5
04.//即该字符串长度为5</FONT>
复制代码二、常用方法
1IsNullOrEmpty():判断字符串是否为空或者为null
举例如下:
01.<FONTface=微软雅黑>string str = “”;
02.if(string.IsNullOrEmpty(str))
03.{
04.Console.WriteLine(“该字符串为空,或为null”);
05.}
06.else
07.{
08.Console.WriteLine(str);
09.}
10.//输出结果为:该字符串为空,或为null
11.//这里,stringstr=null,输出结果也为:该字符串为空,或为null
12.//注意:该方法为静态方法,调用时必须 类名.方法名 调用。</FONT>
复制代码
2ToCharrArry():将string转换成char数组
举例如下:
01.   string str = “hello”;
02.   char[] c = str.ToCharArray();
03.   c[1] = ‘a’;
04.   Console.WriteLine(new string(c));
05.//输出结果为:hallo
06.//因为字符串的不可改变性,要修改字符串中的某个字符,必须ToCharArray()拆分成一个char数组。
复制代码
3ToLower() :将一个字符串转换成小写。
举例如下:
01.stringstr = “HELLO”;
02.strings = str.ToLower();
03.Console.WriteLine(s);
04.//输出结果:hello
05.//注意:必须声明一个变量来接受返回值(s),因为字符串的不可改变性。
复制代码
4Equals():将一个字符换转换成大写
举例如下:
01.stringstr = “hello”;
02.strings = str.Equals();
03.Console.WriteLine(s);
04.//输出结果为:HELLO
复制代码
5Equals():比较两个字符串是否相同
举例如下:
01.strings1 =”hello”;
02.strings2 = “HELLO”;
03.if(s1.Equals(s2))
04.{
05.Console.WriteLine(“两个字符串一样“);
06.}
07.else
08.{
09.Console.WriteLine(“两个字符串不一样“);
10.}
11.//输出结果:两个字符串不一样
12.//因为大小写不同,所以两个字符串是不一样
13.
14.
15.strings1 =”hello”;
16.strings2 = “HELLO”;
17.if(s1.Equals(s2StringComparison.OrdinalIgnoreCase))
18.{
19.Console.WriteLine(“两个字符串一样“);
20.}
21.else
22.{
23.Console.WriteLine(“两个字符串不一样“);
24.}
25.//输出结果:两个字符串一样。
26.//这里我们使用了Equals的第二个重载,该重载第二个参数StringComparison.OrdinalIgnoreCase是一个枚举//值,用来忽略大小写。
复制代码
6IndexOf():检索字符串中指定的字符的索引。
举例如下:
01.stringstr = “大家好,我叫小明,我今年12岁了!大家要记住我叫小明哦!“;
02.int n= str.IndexOf(“小明“);
03.Console.WriteLine(n);
04.//输出结果为:6
05.//以为“小明”,即的索引6、“明”的索引为7,即“小明”的索引为67
06.
07.
08.stringstr = “大家好,我叫小明,小明今年12岁了!“;
09.int n= str.IndexOf(“小明“,7);
10.Console.WriteLine(n);
11.//输出结果为:9
12.//这里我们发现9真好是第二个“小明”的索引。因为这里我们调用了IndexOf(string value,int startIndex)这个重载,即 startIndex=检索开始的地方。
13.
14.
15.stringstr = “大家好,我叫小明,小明今年12岁了!“;
16.int n= str.IndexOf(“小胖“);
17.Console.WriteLine(n);
18.//输出结果为:-1
19.//即如果检索不到相应的数据,则返回值为:-1
20.
21.//注意:1IndexOf返回值为int类型
22.              2IndexOf共有8个重载,不仅仅只能传入一个字符串,还能是一个char,还能指定要检索字符的类型等。。。希望自己在使用的过程中都了解一下这些重载。
23.
复制代码
7LastIndexOf():检索字符串中指定字符最后一个的索引。
举例如下:
01.stringstr = “大家好,我叫小明,小明今年12岁了!“;
02.int n= str.LastIndexOf(“小明“);
03.Console.WriteLine(n);
04.//输出结果为:9
05.//这里直接忽略第一个小明,返回最后一个小明的索引。
06.
复制代码
8Substring():截取字符串
举例如下:
01.stringstr = “大家好,我叫小明,小明今年12岁了!“;
02.stringstr1 = str.Substring(4);
03.Console.WriteLine(str1);
04.//输出结果为:我叫小明,小明今年12岁了!
05.//即从索引4开始截取(含4),截取到最后
06.
07.stringage = str.Substring(13,2);
08.Console.WriteLine(age);
09.//输出结果为:12
10.//即从索引13开始截取(13),截取2个字符
复制代码
9Split():将指定字符串按某指定的分隔符进行拆分,拆分将会形成一个字符串的数组并返回
01.//根据一个字符来分割
02.stringname = “||||“;
03.string[]strName = name.Split(‘-‘);
04.for(inti = 0;i < strName.Lengeh;i++)
05.{
06.    Console.Write(strName);
07.}
08.//输出结果为:小|明小|花小|胖小|
09.
10.//根据一个字符串数组来分割
11.string[]strName = name.Split(new string[]{“-“,”|”},StringSplitOptions.RemoveEmptyEntries);
12.for(inti = 0;i < strName.Lengeh;i++)
13.{
14.Console.Write(strName);
15.}
16.//输出结果为:小明小花小胖小美
17.
18.//补充:Split()6个重载,可以传一个char来分割,也可以传一个char[],还可以是string[]
19.
20.
复制代码
10Join():把一个字符串数组中的每个元素,用指定的字符进行连接
举例如下:
01.stringname = “||||“;
02.string[]strName = name.Split(new string[]{“-“,”|”},StringSplitOptions.RemoveEmptyEntries);
03.stringstr = string.Join(““, strName);
04.Console.WriteLine(str);
05.//输出结果: 小★明★小★花★小★胖★小★美
06.//注意:此方法为静态方法
复制代码
11Format():通过占位符来拼接字符串
举例如下:
01.stringname = “小明“;
02.stringsay = string.Format(“我叫{0}”,name);
03.Console.WriteLine(say);
04.//输出结果为:我叫小明
05.//注意:此方法为静态方法
复制代码
12Replce():用指定的字符替换字符串中指定的字符
01.stringsay = “我叫小明,我今年12岁了!“;
02.stringstr = say.Replcae(“小明“,”***”);
03.Console.WriteLine(str);
04.//输出结果为:我叫***,我今年12岁了!
复制代码
13Trim():去掉字符串两端的空格
举例如下:
01.stringname = “小明“;
02.stringstr = name.Trim();
03.Console.WriteLine(str);
04.//输出结果为:小明

在c#中的richTextBox中实现拖拽

时间:2014年02月07日作者:小侃评论次数:0

之前学过如何在TextBox实现文字的拖拽,但是今天在使用RichTextBox时却发现了好多问题,属性框里没有DragDrop和DragEnter事件,可是在帮助文档里发现了是有这个事件的,所以自己便用代码去实现这两个事件,可是在调用OnDragDrop()方法时,却发现没有,很是郁闷,又仔细再帮助文档中看了一番,却发现OnDragDrop是受保护的,突然间有点晕了,呵呵,想想微软不会这么瞎胡闹吧,richTextBox要比TextBox高级多,怎么会不能实现拖拽呢!呵呵,还是仔细的查看帮助文档吧,呵呵,果然被我发现了一个属性:EnableAutoDragDrop,唉,原来微软都帮我们写好了呀,只要你该一下属性值为True就OK了。

但是,这个时候你运行程序,你会发现文字部分可以成功拖拽了,但是我的RichTextBox有嵌入一些控件,默认的拖拽无法实现我的想法,于是就想去事件框里去看看DragDrop和DragEnter事件有了没,结果发现还是没有,就按F12到元数据表里看了一下他们的定义才发现,其实他们是可以在代码中访问并更改的,但是却不是看见的。

//
// Summary:
// Occurs when the user completes a drag-and-drop
[Browsable(false)]
public event DragEventHandler DragDrop;
//
// Summary:
// Occurs when an object is dragged into the control’s bounds.
[Browsable(false)]
public event DragEventHandler DragEnter;

C++与C#对比学习:内存管理

时间:2013年10月24日作者:小侃评论次数:0

我们知道计算机最重要的资源就是CPU和内存了.CPU的话我们貌似不能直接去操作,都是操作系统去管.而内存的话分为内核区和用户区.内核区是由操作系统管理,我们只能通过一些API去间接操作.而用户区就可以让应用程序去使用了.我们编程大部分时候就是在用户内存区中折腾来折腾去.

     C++内存分区

C++的内存一般分为栈(stack),堆(heap),自由存取区,全局/静态存储区,常量存储区,代码存储区.

栈(stack)

这是由系统自动去分配和管理,不用我们去操心.貌似大小就几M吧.有时我们也叫它堆栈.很容易和堆搞混了,还是看着英文爽点.另外这里的heap和数据结构中的堆不同,heap实际数据结构是指针链表.stack到就是数据结构中的栈.

堆(heap)

我们平时说的直接操作内存用的最多的就这个地方了,出问题出的最多的也就是这里.一般是用new去申请一块内存,用完了再delete掉.我们经常听到的啥内存泄露就是你new了一块内存后忘记delete掉了,或者delete时没有采取正确的方式,没能成功delete.

自由存储区

由malloc申请的存储区,用free来释放掉,这是兼容C的.在C++中用new时还会调用类的构造函数,而用malloc时只是给你分配内存,不会调用构造函数.反正在C++中基本上用new和delete就可以了,不用malloc也行的.另外有些人把自由存储区也划分到堆这一组.

全局/静态存储区

我们知道C++作为面向对象,所以一眼望过去都是一个个的类,啥变量,函数都是在类里面.但毕竟它不是纯面向对象.还有些特性是违反类的封装的,比如全局函数和全局变量.函数是存储在代码区.全局变量就存储在全局存储区.不过既然都说了是面向对象自然还是尽量按规矩办事好点,尽量别用全局变量.我们用全局变量时一般是因为某些变量不是属于某一个类的或某一个类的实例.如果是后一种情况我们可以用静态变量来替代.在类中用statics声明一个静态变量.静态变量直接用类名做前缀去访问,不能通过一个实例化的类去访问.它是保存在静态存储区.

常量存储区

像我们用const声明的变量就是常量.注意在C中有点不一样,const声明的变量可不叫常量,只有用define定义的才叫常量,而且这样的常量由于是在预编译阶段替换掉了,所以不用在内存中给常量分配内存了.另外除了用const显式指明是常量,还有种特殊情况隐式的是常量.char * pChar = “i am const”; //这个字符串就是一个常量,然后指针pChar指向它.

注意如果是这样string str = “i am string”; //这个双引号中的就不是常量了.它只是一般的变量值,存储在stack中.char*这是兼容C中的字符串,在C++可以不用它,用string好了.当然有时调用API或者和C交互还是要用到char*,这时可以把string ,char*互相转换下.

代码区

代码和函数就都保存在这个区.函数名相当于是个隐式的指针,我们调用某个函数时是使用函数名,函数名就指向代码区中具体的函数代码.

 

另外一种划分法是分为:文本段(.text), 数据段(.data), stack,heap四种.

其中文本段是只读的,所以源代码,函数都放这.另外常量也放在这里.

数据段就是保存全局变量或静态变量

stack和heap跟上面说的就一样了.

C#内存分区

由于直接操作内存会经常出问题,所以C#干脆连指针都不让你用,内存也不让你直接操作.CLR(common language runtime)有点像java的JVM,它给你去管理内存.

所以C#的内存分区没那么复杂,直接一个stack,和heap.stack跟C++差不多一样,还是系统去管.heap就是所谓的托管堆,由CLR替我们管理.当然heap里面可能还会分些啥区,但我们就不用去管那么多了,反正人家CLR给我们代劳了啊.C#中有值类型和引用类型的概念.所有基本类型加上struct都是值类型,是保存在stack中.而且string和数组还有自己定义的class都是分两部分保存,具体内容保存在heap中,但stack中保存有它们在heap中的内存地址(32位系统中就4字节,64位系统就8字节),觉得这其实非常像个指针了 .

 

C++直接操作内存与C#托管内存的优劣

很多人都讨论过这个问题,反正各执一词,各有各的道理.C++直接操作内存效率高,C#和Java中间隔了一层效率肯定差远了.但C#,java中不会再有那么多因直接操作内存而带来的问题.其实我们可以举个简单的比喻.就说玩QQ拖拉机或斗地主吧.你牌好时可以自己玩,牌差时不想玩就来个托管,让机器给你代劳.

如果你打牌技术非常厉害你自己打肯定比机器托管厉害,如果你不太会打牌还不如机器托管打的好.

用C++直接玩内存就相当于你自己打牌,而用C#,Java中的托管内存就相当于托管让机器给你玩牌.所以如果你技术非常厉害就用C++占优势点,不然的话用C#,java占优势点.

当然其实说到底语言只是一个工具,我们的目的是编写个有用的系统出来.所以如果一个系统本身的商业逻辑就非常的复杂的,比如大型web网站,你还要再纠缠在一些复杂的语法细节上就更复杂了 .所以用C#,java这样的开发效率更高.另外一个就是类库越多对我们来说也越好,很多事别人帮你做好了,你直接拿来用就好.而且很多类库都是些牛人写的,比你自己写的强多了.

C#不区分大小写的字符串替换(Replace)函数

时间:2013年09月14日作者:小侃评论次数:0

在.NET中,不调用C++/CLI,进行字符串替换有好几种方法:

1、最常用的,就是String实例.Replace(),但这个不能忽略大小写。

2、System.Text.Regex(Regular Expression正则表达式),大家都估计到它的效率不高,虽然它支持忽略大小写。

3、String.SubString()循环,查找要替换的子字符串的位置,截取,然后字符串相加,大家也估计到,数量少(在codeproject.com上曾有文章讨论过和StringBuilder的临届值是600次)的情况下会比StringBuilder快。

4、跟3一样,唯一区别就是字符累加用StringBuilder,数量少的情况下比字符累加要慢,但过了临届值就要快。

5、引用Microsoft VisualBasic RunTime(Microsoft.VisualBasic.DLL),里面有一个Strings.Replace,效率非常高,其原理就是:Split()再Join(),其中Split支持忽略大小写的秘诀就是调用了System.Globalization.CultureInfo,也就是所谓的国际化,其实要实现字符串的替换代码量不多,但要兼容各种语言(非编程语言,是交流语言),那就得多花几倍的代码了。

6、不想用VB运行库的朋友,可以用Reflector配合Denis Bauer’s Reflector.FileDisassembler把Microsoft.VisualBasic.DLL中的Strings的Replace和相关函数抽取出来(C#),然后修补一下就可以单独使用了(我这明显是吃饱了撑着,VB专家装配脑袋指出我这是浪费时间,因为本身Microsoft VisualBasic运行库就包括在.NET Framework中)。
实战

以下是测试代码:
static void Main(string[] args)
{
string segment = “中华aBc共和国”;
string source;
string pattern = “abc”;
string destination = “人民”;
string result = “”;
const long count = 1000;
StringBuilder pressure = new StringBuilder();
HiPerfTimer time;

for (int i = 0; i < count; i++)
{
pressure.Append(segment);
}
source = pressure.ToString();

//regexp
time = new HiPerfTimer();
time.Start();
for (int i = 0; i < count; i++)
{
result = Regex.Replace(source, pattern, destination, RegexOptions.IgnoreCase);
}
time.Stop();

Console.WriteLine(“regexp    =” + time.Duration + “:”);
//vb
time = new HiPerfTimer();
time.Start();
for (int i = 0; i < count; i++)
{
result = Strings.Replace(source, pattern, destination, 1, -1, CompareMethod.Text);
}
time.Stop();

Console.WriteLine(“vb        =” + time.Duration + “:”);
//vbReplace
time = new HiPerfTimer();
time.Start();
for (int i = 0; i < count; i++)
{
result = VBString.Replace(source, pattern, destination, 1, -1, StringCompareMethod.Text);
}
time.Stop();

Console.WriteLine(“vbReplace =” + time.Duration + “:” + result);
//substring
time = new HiPerfTimer();
time.Start();
for (int i = 0; i < count; i++)
{
result = StringHelper.ReplaceText(source, pattern, destination, StringHelper.CompareMethods.Text);
}
time.Stop();

Console.WriteLine(“substring =” + time.Duration + “:”);
//substring with stringbuilder
time = new HiPerfTimer();
time.Start();
for (int i = 0; i < count; i++)
{
result = StringHelper.ReplaceTextB(source, pattern, destination, StringHelper.CompareMethods.Text);
}
time.Stop();

Console.WriteLine(“substringB=” + time.Duration + “:”);
Console.ReadLine();
}

说明

这个代码演示了上述几种方法:要把字符串”中华aBc共和国”中的”abc”替换为”人民”,注意:源子字符串是”aBc”,要替换的是”abc”,这里目的是要测试不区分大小写。

为了测试效率,我特意先把测试字符串累加1000次,然后循环测试1000次。
结果

以下是测试结果:
regexp      =1.38308285017339 //这是正则表达式,第3快;
vb            =0.525978828344589 //这是引用Microsoft VisualBasic RunTime的,次快;
vbReplace=0.522997341400086 //这就是用reflector改为C#的,最快;
substring  =21.8573638474698 //这是string.substring +,最慢
substringB=14.6346693500287 //这是string.substring StringBuilder,次慢,这里凸现了StringBuilder的速度;

这里仅仅是多次测试中的一次,我没有弄平均,大概数字吧,到底是vb快还是reflector的c#快,差不多…

是否应该使用Microsoft VisualBasic RunTime就见仁见智了。

C# INI文件操作类(IniHelper)

时间:2013年08月16日作者:小侃评论次数:0

using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;

namespace Updater
{
class IniHelper
{
//文件INI名称
public string Path;

/**/
////声明读写INI文件的API函数
[DllImport(“kernel32”)]

private static extern long WritePrivateProfileString(string section, string key, string val, string filePath);
[DllImport(“kernel32”)]

private static extern int GetPrivateProfileString(string section, string key, string def, StringBuilder retVal, int
size, string filePath);
//类的构造函数,传递INI文件名
public IniHelper(string inipath)
{
//
// TODO: Add constructor logic here
//
Path = inipath;
}

//写INI文件
public void WriteValue(string section, string key, string value)
{
WritePrivateProfileString(section, key, value, this.Path);

}

//读取INI文件指定
public string ReadValue(string section, string key)
{
StringBuilder temp = new StringBuilder(255);
int i = GetPrivateProfileString(section, key, “”, temp, 255, this.Path);
return temp.ToString();

}
/**/
/// <summary>
/// 验证文件是否存在
/// </summary>
/// <returns>布尔值</returns>
public bool ExistFile()
{
return File.Exists(this.Path);
}

/// <summary>
/// 删除ini文件下所有段落
/// </summary>
public void ClearAllSection()
{
WriteValue(null, null, null);
}
/// <summary>
/// 删除ini文件下personal段落下的所有键
/// </summary>
/// <param name=”Section”></param>
public void ClearSection(string Section)
{
WriteValue(Section, null, null);
}

}
}

C#编写软件实现在Vista、Win7、win8桌面版下“以管理员身份运行”验证过程

时间:2013年08月16日作者:小侃评论次数:0

VISTA、Windows 7、Windows 8都使用了UAC来控制程序访问,对于一些需要使用管理员身份运行的程序就得右键以管理员身份运行。

C#编程中可以使程序自动使用管理员身份运行,也就是我们常常看到一些程序的图标上会冒出个盾牌。

开启软件编译使用Administrator验证运行的方法如下:

在源码的Properties目录中找到 app.manifest, 将其中level=”asInvoker” 改成 level=”requireAdministrator”就可以了。

如果没有app.manifest文件可以打开项目属性,找到安全性项,勾上启用 ClickOnce 安全设置,这时会生成app.manifest文件,然后再把勾去掉,不要选上。

这样你重新编译,你的程序图标上就会出现个小盾牌了,就自动以管理员身份运行你的程序,无需右键打开。