王朝网络
分享
 
 
 

C#编程实践

王朝c#·作者佚名  2006-11-24
宽屏版  字体: |||超大  

最近一段时间学习使用C#编程,因为用惯了Delphi,发现C#类库还是不太完善(我用的是.Net Framework 1.0,不知道.Net Framework 1.1有哪些改进),此外Visual Studio 2002也有不完善的地方,不知道Visual Studio 2003有哪些改进呢。比如没有提供Ini文件的访问类,比如输入框不能像Delphi那样指定默认的输入法(更正:为了控制输入法,.NET类库在System.Windows.Forms.InputLanguage类中提供了支持),为此我不得不写了一个Ini访问类和根据输入法名称切换输入法的类。

问题列表:

C# Ini访问类

C# 输入法切换类

使用C#读写文件

格式化字符串

从Assemble中加载自定义资源

对StringCollection进行排序

C#Builder的Open Tools Api的Bug

使用反射动态设定组件属性

将字符串复制到剪贴板

获取程序文件的版本信息

利用反射动态加载Assembly动态执行类型方法

其他问题

C# Ini访问类

using System;

using System.IO;

using System.Runtime.InteropServices;

using System.Text;

using System.Collections;

using System.Collections.Specialized;

using System.Windows.Forms;

namespace SharpPlus.Ini {

/// <summary>

/// 一个模仿Delphi的TIniFile的类

/// 修订:1.1 修正了对中文系统的支持。

/// 1.2 增加了UpdateFile方法,实现了对Win9x的支持

/// 1.3 增加了读写布尔,整数的操作

/// 1.4 修正了写Ini虽然成功,但是会抛出异常的错误

/// 1.5 ReadString返回的是Trim后的字符串

/// 1.6 统一并扩大了读写缓冲区的大小

/// </summary>

public class IniFile {

public string FileName; //INI文件名

//声明读写INI文件的API函数

[DllImport("kernel32")]

private static extern bool WritePrivateProfileString(string section,string key,string val,string filePath);

[DllImport("kernel32")]

private static extern int GetPrivateProfileString(string section,string key,string def, byte[] retVal,int size,string filePath);

//类的构造函数,传递INI文件名

public IniFile(string AFileName) {

// 判断文件是否存在

FileInfo fileInfo=new FileInfo(AFileName);

//Todo:搞清枚举的用法

if ((!fileInfo.Exists)) //|| (FileAttributes.Directory in fileInfo.Attributes))

throw(new ApplicationException("Ini文件不存在"));

//必须是完全路径,不能是相对路径

FileName = fileInfo.FullName;

}

//写INI文件

public void WriteString(string Section,string Ident,string Value) {

if (!WritePrivateProfileString(Section, Ident,Value,FileName))

{

// Todo:抛出自定义的异常

throw(new ApplicationException("写Ini文件出错"));

}

}

//读取INI文件指定

public string ReadString(string Section,string Ident, string Default) {

//StringBuilder Buffer = new StringBuilder(255);

Byte[] Buffer=new Byte[65535];

int bufLen=GetPrivateProfileString(Section,Ident,Default,Buffer, Buffer.GetUpperBound(0),FileName);

//必须设定0(系统默认的代码页)的编码方式,否则无法支持中文

string s=Encoding.GetEncoding(0).GetString(Buffer);

s=s.Substring(0,bufLen);

return s.Trim();

}

//读整数

public int ReadInteger(string Section, string Ident , int Default){

string intStr=ReadString(Section, Ident, Convert.ToString(Default));

try{

return Convert.ToInt32(intStr);

}

catch (Exception ex){

Console.WriteLine(ex.Message);

return Default;

}

}

//写整数

public void WriteInteger(string Section,string Ident, int Value){

WriteString(Section, Ident, Value.ToString());

}

//读布尔

public bool ReadBool(string Section, string Ident, bool Default){

try

{

return Convert.ToBoolean(ReadString(Section, Ident, Convert.ToString(Default) ));

}

catch (Exception ex){

Console.WriteLine(ex.Message);

return Default;

}

}

//写Bool

public void WriteBool(string Section, string Ident , bool Value){

WriteString(Section, Ident, Convert.ToString(Value));

}

//从Ini文件中,将指定的Section名称中的所有Ident添加到列表中

public void ReadSection(string Section, StringCollection Idents) {

Byte[] Buffer=new Byte[16384];

//Idents.Clear();

int bufLen=GetPrivateProfileString(Section, null, null, Buffer, Buffer.GetUpperBound(0),

FileName);

//对Section进行解析

GetStringsFromBuffer(Buffer, bufLen, Idents);

}

private void GetStringsFromBuffer(Byte[] Buffer, int bufLen, StringCollection Strings) {

Strings.Clear();

if (bufLen!=0) {

int start=0;

for(int i=0; i < bufLen; i++) {

if ((Buffer[i] == 0) && ((i-start)>0)) {

String s=Encoding.GetEncoding(0).GetString(Buffer, start, i-start);

Strings.Add(s);

start=i+1;

}

}

}

}

//从Ini文件中,读取所有的Sections的名称

public void ReadSections(StringCollection SectionList) {

//Note:必须得用Bytes来实现,StringBuilder只能取到第一个Section

byte[] Buffer = new byte[65535];

int bufLen=0;

bufLen = GetPrivateProfileString(null, null, null,Buffer,

Buffer.GetUpperBound(0), FileName);

GetStringsFromBuffer(Buffer, bufLen, SectionList);

}

//读取指定的Section的所有Value到列表中

public void ReadSectionValues(string Section, NameValueCollection Values) {

StringCollection KeyList=new StringCollection();

ReadSection(Section, KeyList);

Values.Clear();

foreach(string key in KeyList) {

Values.Add(key, ReadString(Section, key, ""));

}

}

//清除某个Section

public void EraseSection(string Section) {

//

if (!WritePrivateProfileString(Section, null, null, FileName)) {

throw(new ApplicationException("无法清除Ini文件中的Section"));

}

}

//删除某个Section下的键

public void DeleteKey(string Section, string Ident) {

WritePrivateProfileString(Section, Ident, null, FileName);

}

//Note:对于Win9X,来说需要实现UpdateFile方法将缓冲中的数据写入文件

//在Win NT, 2000和XP上,都是直接写文件,没有缓冲,所以,无须实现UpdateFile

//执行完对Ini文件的修改之后,应该调用本方法更新缓冲区。

public void UpdateFile() {

WritePrivateProfileString(null, null, null, FileName);

}

//检查某个Section下的某个键值是否存在

public bool ValueExists(string Section, string Ident) {

//

StringCollection Idents=new StringCollection();

ReadSection(Section, Idents);

return Idents.IndexOf(Ident)>-1;

}

//确保资源的释放

~IniFile(){

UpdateFile();

}

}

}

C# 输入法切换类

C#的编辑组件只有ImeMode属性,没有Delphi中组件的ImeName属性,下面的类可以用来根据ImeName设定当前系统的Ime。(更正:为了控制输入法,.NET类库在System.Windows.Forms.InputLanguage类中提供了支持。)

using System;

using System.Runtime.InteropServices;

using System.Collections;

using Microsoft.Win32;

namespace Screen

{

/// <summary>

/// Ime 的摘要说明。

/// 实现本地化输入法

/// 参考Delphi中的实现

/// </summary>

public class Ime

{

[DllImport("user32")]

private static extern uint ActivateKeyboardLayout(uint hkl, uint Flags);

[DllImport("user32")]

private static extern uint LoadKeyboardLayout(string pwszKLID,uint Flags);

[DllImport("user32")]

private static extern uint GetKeyboardLayoutList(int nBuff, uint[] List);

private static Hashtable FImes;

public static uint KLF_ACTIVATE = 1;

public Ime()

{

//

// TODO: 在此处添加构造函数逻辑

//

}

//设定当前Ime,使用方法Ime.SetImeName("中文 (简体) - 拼音加加");

public static void SetImeName(string ImeName)

{

//字符串形式

if (FImes==null)

GetImes();

uint id = Convert.ToUInt32(FImes[ImeName]);

SetIme(id);

}

public static void SetIme(uint ImeId)

{

//Id样式

if (ImeId>0)

ActivateKeyboardLayout(ImeId, KLF_ACTIVATE);

}

//获得所有的Ime列表

public static Hashtable GetImes()

{

if (FImes==null)

FImes=new Hashtable();

else

return FImes;

uint[] KbList=new uint[64];

uint TotalKbLayout = GetKeyboardLayoutList(64, KbList);

for (int i=0 ; i< TotalKbLayout ; i++)

{

string RegKey=String.Format("System\\CurrentControlSet\\Control\\Keyboard Layouts\\{0:X8}",KbList[i]);

RegistryKey rk=Registry.LocalMachine.OpenSubKey(RegKey);

if (rk==null)

continue;

string ImeName=(string)rk.GetValue("layout text");

if (ImeName==null)

continue;

FImes.Add(ImeName, KbList[i]);

}

return FImes;

}

}

}

其他IDE及类库问题

Visual Studio 2002 IDE的问题

监视窗口的变量在没有走到调试点时不允许删除。

不支持事件重新命名。

新建的窗口有时莫名其妙地就没有了标题。

经常启动程序后,看不到界面,必须停止调试重新运行才行。

.Net Framework 1.0的问题

窗体没有ActiveControl属性,这点比较不爽。

TabControl中的选项卡的标题页无法隐藏,因此无法用来实现专家向导的界面。

TreeView的Sorted属性为True时,insert一个节点会被自动排序。没有提供定制排序的功能。

事件传过来的坐标是系统坐标,而不是组件坐标,需要调用PointToClient转换一下才行。

OleDbDataReader是独占连接的方式,一个DataReader不关闭的话,其他数据集都无法使用。而Delphi的DBExpress虽然也是单向游标,但是一个组件使用时不影响其他数据组件的使用。

对于Access的支持非常不好,使用like进行模糊查询有时会导致缓冲区溢出。

使用C#读写文件

下面的代码示意了如何将一个数据集中的数据写入文件。

try

{

DbConn.Open();

OleDbDataReader Reader = CommandLog.ExecuteReader();

try

{

StreamWriter sw = new StreamWriter(saveFile, false,

Encoding.ASCII);

while (Reader.Read() )

{

String s=Reader["IP"]+" - - ";

DateTime dt=(DateTime)Reader["VisitDate"];

//使用英美的日期格式格式化日期字符串

CultureInfo ci = new CultureInfo("en-US");

String VisitDate=dt.ToString("dd/MMM/yyyy:hh:mm:ss", ci);

s= s+ "["+VisitDate+" -0700] ";

String Ref=(String)Reader["Referer"];

//如果没有Refer,则

if (Ref.Trim()!="")

{

s=s+"\"GET / HTTP/1.1\" 200 23989 \""+Ref+"\" \""+Reader["UserAgent"]+"\"";

sw.WriteLine(s);

}

}

sw.Close();

}

finally

{

Reader.Close();

}

}

catch (Exception e)

{

Console.WriteLine("发生异常\n{0}", e.Message);

}

}

格式化字符串

string result=String.Format("Select * from TblCategory where (ParentId={0}) order by CategoryIndex", Pid);

C#Builder Open Tools Api的Bug

1. CodeDom无法获得构造函数的行号。

2. 无法获得Internal Protected 成员。

3. 无法将文件从项目中删除

4. C#Builder IOTAModuleInfo.ModuleType返回的全是空串

5. 不支持IOTASearchOptions接口。

使用反射动态设定组件属性

通过typeof(Component)获得Type对象,然后调用GetProperties获得属性列表,对于特定属性可以通过

GetProperty方法获得PropertyInfo对象,然后调用PropertyInfo对象的SetValue来设定值。示例如下:

System.Type btnType=button1.GetType();

PropertyInfo[] props=btnType.GetProperties();

foreach (PropertyInfo prop in props){

if (prop.Name=="Text")

prop.SetValue(button1, "test", null);

}

要想通知IDE组件属性的变更,加下面代码示例:

PropertyDescriptor backColorProp =

TypeDescriptor.GetProperties(Control)["BackColor"];

if (backColorProp != null) {

backColorProp.SetValue(Control, Color.Green);

也可以通过IComponentChangeService来实现通知。

对StringCollection进行排序

StringCollection类对应于Delphi中的TStringList类,但是同TStringList类相比,缺少了排序的功能,为此我写了一个方法,可以对StringCollection进行排序。

//对StringCollection进行排序

public static void Sort(StringCollection Strs,bool CaseSensitive) {

IComparer comparer=null;

if (CaseSensitive)

comparer=Comparer.DefaultInvariant;

else

comparer=CaseInsensitiveComparer.DefaultInvariant;

QuickSort(Strs, 0, Strs.Count - 1, comparer);

}

private static void QuickSort(StringCollection Strs, int L,int R, IComparer comparer) {

while (true) {

int I = L;

int J = R;

int P = (L + R) / 2;

while (true) {

while (comparer.Compare(Strs[I], Strs[P]) < 0)

I++;

while (comparer.Compare(Strs[J], Strs[P]) > 0)

J--;

if (I <= J) {

ExchangeStrings(Strs, I, J);

if (P == I)

P = J;

else if (P == J)

P = I;

I++;

J--;

}

if (I > J)

break;

}

if (L < J)

QuickSort(Strs, L, J, comparer);

L = I;

if (I >= R)

break;

}

}

//交换字符串的位置

public static void ExchangeStrings(StringCollection Strs, int I, int J ) {

string si=Strs[I];

string sj=Strs[J];

Strs.RemoveAt(I);

Strs.Insert(I,sj);

Strs.RemoveAt(J);

Strs.Insert(J,si);

}

从Assemble中加载自定义资源

用Resourcer向Resx文件中添加图标、位图或者字符串等资源后,调用下面示例代码就可以加载资源了:

//加载资源

ResourceManager rm =

new ResourceManager("SharpPlus.Resources", Assembly.GetExecutingAssembly());

Icon LogoIcon=(Icon)rm.GetObject("Logo.ico");

将字符串复制到剪贴板

Clipboard.SetDataObject("Test");

获取程序文件的版本信息

//获得运行时的Assembly的版本信息

public static string GetAssemblyVersion()

{

Assembly myAssembly =Assembly.GetExecutingAssembly();

FileVersionInfo myFileVersion =FileVersionInfo.GetVersionInfo(myAssembly.Location);

return string.Format("{0}.{1}.{2}",myFileVersion.FileMajorPart, myFileVersion.FileMinorPart, myFileVersion.FileBuildPart);

}

利用反射动态加载Assembly动态执行类型方法

string dllName="OverSeer.dll";

Type t=ReflectionUtils.GetType(dllName, "uDbg.Unit");

dt=ReflectionUtils.GetType(dllName, "uDbg.TNxDebugger");

//MethodInfo mi=t.GetMethod("Debugger", BindingFlags.Static | BindingFlags.Public);

//Object debugger=mi.Invoke(null,null);

if (t==null)

return;

//动态执行静态Debugger方法

debugger=t.InvokeMember("Debugger", BindingFlags.Public| BindingFlags.Static | BindingFlags.InvokeMethod, null,null, null);

//根据Assembly名称和类型名称动态获取类型元数据

public static Type GetType(string AssemblyName, string TypeName)

{

FileInfo info=new FileInfo(AssemblyName);

if (!info.Exists)

return null;

Assembly a=Assembly.LoadFrom(AssemblyName);

//Todo:处理异常

return a.GetType(TypeName);

}

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
>>返回首页<<
推荐阅读
 
 
频道精选
 
静静地坐在废墟上,四周的荒凉一望无际,忽然觉得,凄凉也很美
© 2005- 王朝网络 版权所有