分类目录归档:C#

将VB.NET网站转换成C#的全过程

前两天看到一个比较不错的网站,可惜是用vb.net写的,俺弄不大明白,于是心血来潮想把它全部转换成C#代码的。花了N长时间,问了几多人,费了不少神,总算是能让网站在C#下马马虎虎的跑了,不小心还喜欢蹦出个鲜红夺目的错误信息,真是让人战战兢兢。

总结的经验教训就是:没事别再这么干了,有这些闲功夫不如把这两种语言都弄懂,或者把网站重写。大家看看我转化的详细过程,估计也会知难而退的。

一、代码转化的几种方式

1、 通过工具直接转化

第一款:VB.net to C# Converter

http://www.vbconversions.com/index.html

 

VB.net to C# Converter是一款离线转换软件,安装简单,提供试用版,而且试用版永不过期,但是试用版只能翻译不超过600行源码的工程。VB.net to C# Converter将用户的VB.net项目用C#语言重新编写,同时变量名、注释行都被保留下来。它具有完备的功能,提供专业的报告生成工具,而且能够对转换过程中的错误生成错误记录,并且在此基础上提供错误分析和提供修改建议。总之,它是一款充分为使用者考虑的,功能完备的转换工具。

它提供多种类型工程的转换,包括Windows Forms 工程、Console 工程、Windows Control 库、Web Control 库、Web Services工程、Windows Service 工程。提供多种形式的转换,包括单一工程、多个工程、交互式代码转换、命令行形式转换。大多数的VB 函数都能转换为相应的 C# 功能,而且注解等也能得到很好的转换。可以使用向导,并提供在线帮助。转换准确率高达99%。

但是,它不支持中文,中文注解会生成乱码。完整版需要购买。(宋立桓老师)

正式版本收费在100美元左右,好像只能对工程文件进行转换,我手头的代码没有工程文件,没用这个软件。

第二款:Convert Assistant

http://www.wimontheweb.com/ca_main.aspx

这款口碑也不错,看人家的介绍:

Our assistant will help you to translate all your VB.NET projects to C#. She does this in a very textual way. Therefore, you don’t need to have any references or additional components on your computer. As long as the syntax is correct, she’ll be pleased to help you. Next thing you know, your source code has become sharp and crystal-clear!

 
好像也不提供免费,有钱的大淫,可以买来玩玩。

第三款 TransKing for Visual Studio .NET

http://www.e-iceblue.com/

Price:   EUR 133.40 / USD 149.00
Shipment:   Full version in an e-mail attachment
Platform:   .NET VS.NET 2002 or VS.NET 2003
Version:   1.56

 

 

 

 

 

自称是市面上最好的VB & VB.net into C#工具,我反正是没用过,149美元能买多少馅饼、火腿肠、方便面啊,要是都换成白面馒头,可有一大车呢。

另外贴一款VB.NET to C# 的工具地址,这类解决方案较多,就不赘述了。

http://csharpconverter.claritycon.com/Default.aspx

2、在线WebService调用

http://www.kamalpatel.net/

微软最有价值专家的解决方案,网上有多家BLOG介绍过,他的C# to VB.NET开发的相当成功,国内有款转换软件叫“WebServiceDemo.exe”,就是调用他的引用。后来推出的VB.NET to C#版本,名气虽大,就是经常不能用。

3、 在线转换服务

将转换逻辑封装在服务器上,你把代码Ctrl+C上去,点“转换”,人家就把转换好的代码给你显示在页面上。

Developer fusion

http://www.developerfusion.co.uk/utilities/convertvbtocsharp.aspx

使用方便,而且免费。只是目前正在试用阶段,转换后程序错误较多,并且在转换后的代码里不包含注释,这是因为转换后的代码在返回之前,首先被翻译为抽象树,而目前的这种树状结构把注释都忽略了。(宋立桓老师)

另一款http://www.icsharpcode.net/,这个不怎么样。

二、vb.net与c#的风格转化

1、大小写

怎么说好呢,vb.net是对大小写不敏感的,而C#恰恰相反,大多数转换后的代码还是小写,所以工作量就来了,啥也不用说了,改吧。

常用的:.Replace、SqlConnection、ConfigurationSettings.AppSettings、SqlDataAdapterDataTable、Selected、.SelectedItem、DataSet、DataColumn、DataSource、DataColumn()、.Tables、.Fill.DataBind()、.ColumnName、.DataType、.Add、.Rows、.Count、System.Type.GetType、.ToString()……….

2、用法

Vb.net很多地方的用法和C# 不同,没办法,还得手工改,比如:

Mid—————————————–à.Substring()

Trim—————————————-à.Trim()

Len——————————————à.Length()

page.ispostback()————————-àPage.IsPostBack

Session(“”)———————————àSession[“”]

dt.rows(i).item(“abc”)——————–àdt.Rows[i][“abc”]

ds.tables(“abc”)—————————àds.Tables[“abc”]

.items(i). ———————————-à.Items[i]

改的时候用DW整目录一搜,出来8000多条记录,都得手工逐条改,进度非常慢。后来请教了Ectotherm,改用正则匹配,速度快多了。

不过复杂的语句还是要靠手工修改,正则很难构造,而且经常匹配出错。

EmEditor.exe对字符正则查找替换支持的非常好,强烈推荐。(有点像中插广告)

回想起那段往事,真是没事找事。

3、函数

在下VB.NET可以使用的许多函数和方法到了C#就不灵了,比如IsNumeric再比如isdbnull,都改成这份上了,总不能半途而废吧,请教谷坤的结果就是自己写一个 Isnumeric然后在页面中调用。

这点倒不用着急,已经有好事者帮咱们做好了。

IsNumeric in C#, WHY NOT?

http://dotnet.org.za/deonvs/archive/2004/07/06/2579.aspx

具体方法是构建一个func.inc,然后在每个调用IsNumric方法的页面添加

<!– #include file=”..func.inc” –>,func.inc代码如下:

public static bool IsNumeric(object Expression)

{

bool isNum;

double retNum;

isNum = Double.TryParse(Convert.ToString(Expression), System.Globalization.NumberStyles.Any,System.Globalization.NumberFormatInfo.InvariantInfo, out retNum );

return isNum;

}

三、与格式转化相关的网站资料
1、VB.net与C#对照表,包括以下方面

http://www.harding.edu/USER/fmccown/WWW/vbnet_csharp_comparison.html

 

2、From VB.NET to C# and Back Again
Darren Neimke 和Scott Mitchell撰写的,有关VB.net 和C#代码互转的专作。

http://www.4guysfromrolla.com/webtech/012702-1.shtml

3、C# to VB.NET Translator,如何转化C#为VB.NET指导类文章。

http://authors.aspalliance.com/aldotnet/examples/translate.aspx

四、专家意见

哈哈,搬出专家的意见更显得有说服性,下面是我请教微软MVP宋立桓老师后,他给出的指导性、建设性和前瞻性意见,软件说明部分我作了直接引用:

我只能提供方法和原则,首先你可以全面了解两种语言的语法和构造的差别,并可以通过一门语言学习另外一门语言。其次,也可以使用些转换软件,不过,至今却还没有一种工具能够实现100%的无差错转换。因为,大多数的转换软件都是基于字面和语法的转换,而不是基于程序逻辑的转换,所以程序转换过程中就可能因为程序逻辑不被理解而发生错误。因此使用工具转换后我们还是要进行测试和少量修改的,同时了解一定的C#和VB.net的语法和它们之间的差别对我们还是很有好处的。如果采用手工转换,那么C#和VB.net之间的语法对照表可能对你有用,可以参考以下网址:http://www.harding.edu/USER/fmccown/WWW/vbnet_csharp_comparison.html。

一些注意点:

(1) C#中引用比较和值的比较都使用“==” 关键字,而VB.net 使用“is”关键字做引用比较,

(2) C#中字符连接符和加法运算符都使用“+”

(3) VB.net是大小写不敏感的,

(4) 注释有时不能加载到正确位置http://www.cnblogs.com/cngunner/archive/2006/01/16/318309.html

 

c# string和byte[]转换

byte[] byteArray = System.Text.Encoding.Default.GetBytes(  str  );

反过来也是一样,把byte[]转成string:

string str = System.Text.Encoding.Default.GetString( byteArray );

其实,在System.Text.Encoding class中,还有很多其它有用的方法,像GetChars,从一个byte[]转成一个char[],等等,可以参考MSDN。

另外,还有其它编码方式的,如System.Text.UTF8Encoding class、System.Text.UnicodeEncoding class等,根据不同需要可选不同的class。

http://www.cnblogs.com/baishahe/archive/2008/03/21/1115919.html

 

C#调用c++Dll结构体数组指针的问题

C#调用c++dll文件是一件很麻烦的事情,首先面临的是数据类型转换的问题,相信经常做c#开发的都和我一样把学校的那点c++底子都忘光了吧(语言特性类)。

网上有一大堆得转换对应表,也有一大堆的转换实例,但是都没有强调一个更重要的问题,就是c#数据类型和c++数据类型占内存长度的对应关系。

如果dll文件中只包含一些基础类型,那这个问题可能可以被忽略,但是如果是组合类型(这个叫法也许不妥),如结构体、类类型等,在其中的成员变量的长度的申明正确与否将决定你对dll文件调用的成败。

如有以下代码,其实不是dll文件的源码,而是厂商给的c++例子代码

c++中的结构体申明

typedef struct

{

unsigned charPort;

unsigned longId;

unsigned charCtrl;

unsigned charpData[8];

}HSCAN_MSG;

c++中的函数申明(一个c++程序引用另一个c++的dll文件)

extern “C” int _stdcall HSCAN_SendCANMessage(unsigned char nDevice,unsigned char nPort,HSCAN_MSG *msg,int nLength);

c++中的调用:

….

HSCAN_MSG msg[100];

…..

HSCAN_SendCANMessage(m_nDevice,m_nPort,msg,nFrames);

由上述代码可见,msg是个结构体的数组。

下面是我的c#的代码

c#结构体申明:(申明成)

[StructLayout(LayoutKind.Sequential)]

public struct  HSCAN_MSG

{

// UnmanagedType.ByValArray, [MarshalAs(UnmanagedType.U1)]这个非常重要,就是申明对应类型和长度的

[MarshalAs(UnmanagedType.U1)]

public byte Port;

[MarshalAs(UnmanagedType.U4)]

public uint nId;

[MarshalAs(UnmanagedType.U1)]

public byte nCtrl;

[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]

public byte[] pData;

};

 

c#函数申明

[DllImport(“HS2106API.dll”)]

public static extern int HSCAN_SendCANMessage(

byte nDevice, byte nPort, HSCAN_MSG[] pMsg, int nLength);

C#函数调用

HSCAN_MSG[] msg = new HSCAN_MSG[1];//发送缓冲区大小可根据需要设置;

for (int yy = 0; yy < msg.Length; yy++)

{

msg[yy] = new HSCAN_MSG();

}

//…结构体中的成员的实例化略

HSCAN_SendCANMessage(0x0, 0x0, msg, 1)

 

那些只能用指针不能用结构体和类的地方

 

 

c++中的结构体申明

typedef struct

{

unsigned charPort;

unsigned longId;

unsigned charCtrl;

unsigned charpData[8];

}HSCAN_MSG;

c++中的函数申明(一个c++程序引用另一个c++的dll文件)

extern “C” int _stdcall HSCAN_SendCANMessage(unsigned char nDevice,unsigned char nPort,HSCAN_MSG *msg,int nLength);

 

c#中的结构体申明:

[StructLayout(LayoutKind.Sequential)]

public struct HSCAN_MSG

{

[MarshalAs(UnmanagedType.U1)]

public byte Port;

/// <summary>

/// 节点标识,nEFF=1 时(扩展帧),为29 位nEFF=0(标准帧)时,为11 位;

/// </summary>

[MarshalAs(UnmanagedType.U4)]

public uint nId;

[MarshalAs(UnmanagedType.U1)]

public byte nCtrl;

[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]

public byte[] pData;

};

 

c#函数的调用:包含使用指针IntPtr替代结构体数组和读取IntPtr的方法

HSCAN_MSG[] msg1 = new HSCAN_MSG[10];

for (int i = 0; i < msg1.Length; i++)

{

msg1[i] = new HSCAN_MSG();

msg1[i].pData = new byte[8];

}

 

IntPtr[] ptArray = new IntPtr[1];

ptArray[0] = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(HSCAN_MSG)) * 10);

IntPtr pt = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(HSCAN_MSG)));

Marshal.Copy(ptArray, 0, pt, 1);

 

 

int count = HSCAN_ReadCANMessage(0x0, 0,pt, 10);

 

textBoxStatus.Text += “rn” + “读取0口:” + count.ToString() + “帧数据”;

for (int j = 0; j < 10; j++)

{

msg1[j] =

(HSCAN_MSG)Marshal.PtrToStructure((IntPtr)((UInt32)pt+ j * Marshal.SizeOf(typeof(HSCAN_MSG)))

, typeof(HSCAN_MSG));

textBoxStatus.Text += “rn收到0口” + Convert.ToByte(msg1[j].pData[0]).ToString()

+ “|” + Convert.ToByte(msg1[j].pData[1]).ToString()

+ “|” + Convert.ToByte(msg1[j].pData[2]).ToString()

+ “|” + Convert.ToByte(msg1[j].pData[3]).ToString()

+ “|” + Convert.ToByte(msg1[j].pData[4]).ToString()

+ “|” + Convert.ToByte(msg1[j].pData[5]).ToString()

+ “|” + Convert.ToByte(msg1[j].pData[6]).ToString()

+ “|” + Convert.ToByte(msg1[j].pData[7]).ToString();

}

http://www.cnblogs.com/badnewfish/archive/2009/11/10/1599648.html

 

C#串口通讯

网上的原版的串口通讯类N年前就出了的:
using System;
using System.Runtime.InteropServices;

namespace JustinIO {
class CommPort {

public string PortNum;
public int BaudRate;
public byte ByteSize;
public byte Parity; // 0-4=no,odd,even,mark,space
public byte StopBits; // 0,1,2 = 1, 1.5, 2
public int ReadTimeout;

//comm port win32 file handle
private int hComm = -1;

public bool Opened = false;

//win32 api constants
private const uint GENERIC_READ = 0x80000000;
private const uint GENERIC_WRITE = 0x40000000;
private const int OPEN_EXISTING = 3;
private const int INVALID_HANDLE_VALUE = -1;

[StructLayout(LayoutKind.Sequential)]
public struct DCB {
//taken from c struct in platform sdk
public int DCBlength;           // sizeof(DCB)
public int BaudRate;            // 指定当前波特率 current baud rate
// these are the c struct bit fields, bit twiddle flag to set
public int fBinary;          // 指定是否允许二进制模式,在windows95中必须主TRUE binary mode, no EOF check
public int fParity;          // 指定是否允许奇偶校验 enable parity checking
public int fOutxCtsFlow;      // 指定CTS是否用于检测发送控制,当为TRUE是CTS为OFF,发送将被挂起。 CTS output flow control
public int fOutxDsrFlow;      // 指定CTS是否用于检测发送控制 DSR output flow control
public int fDtrControl;       // DTR_CONTROL_DISABLE值将DTR置为OFF, DTR_CONTROL_ENABLE值将DTR置为ON, DTR_CONTROL_HANDSHAKE允许DTR”握手” DTR flow control type
public int fDsrSensitivity;   // 当该值为TRUE时DSR为OFF时接收的字节被忽略 DSR sensitivity
public int fTXContinueOnXoff; // 指定当接收缓冲区已满,并且驱动程序已经发送出XoffChar字符时发送是否停止。TRUE时,在接收缓冲区接收到缓冲区已满的字节XoffLim且驱动程序已经发送出XoffChar字符中止接收字节之后,发送继续进行。 FALSE时,在接收缓冲区接收到代表缓冲区已空的字节XonChar且驱动程序已经发送出恢复发送的XonChar之后,发送继续进行。XOFF continues Tx
public int fOutX;          // TRUE时,接收到XoffChar之后便停止发送接收到XonChar之后将重新开始 XON/XOFF out flow control
public int fInX;           // TRUE时,接收缓冲区接收到代表缓冲区满的XoffLim之后,XoffChar发送出去接收缓冲区接收到代表缓冲区空的XonLim之后,XonChar发送出去 XON/XOFF in flow control
public int fErrorChar;     // 该值为TRUE且fParity为TRUE时,用ErrorChar 成员指定的字符代替奇偶校验错误的接收字符 enable error replacement
public int fNull;          // eTRUE时,接收时去掉空(0值)字节 enable null stripping
public int fRtsControl;     // RTS flow control
/*RTS_CONTROL_DISABLE时,RTS置为OFF
RTS_CONTROL_ENABLE时, RTS置为ON
RTS_CONTROL_HANDSHAKE时,
当接收缓冲区小于半满时RTS为ON
当接收缓冲区超过四分之三满时RTS为OFF
RTS_CONTROL_TOGGLE时,
当接收缓冲区仍有剩余字节时RTS为ON ,否则缺省为OFF*/

public int fAbortOnError;   // TRUE时,有错误发生时中止读和写操作 abort on error
public int fDummy2;        // 未使用 reserved

public uint flags;
public ushort wReserved;          // 未使用,必须为0 not currently used
public ushort XonLim;             // 指定在XON字符发送这前接收缓冲区中可允许的最小字节数 transmit XON threshold
public ushort XoffLim;            // 指定在XOFF字符发送这前接收缓冲区中可允许的最小字节数 transmit XOFF threshold
public byte ByteSize;           // 指定端口当前使用的数据位   number of bits/byte, 4-8
public byte Parity;             // 指定端口当前使用的奇偶校验方法,可能为:EVENPARITY,MARKPARITY,NOPARITY,ODDPARITY  0-4=no,odd,even,mark,space
public byte StopBits;           // 指定端口当前使用的停止位数,可能为:ONESTOPBIT,ONE5STOPBITS,TWOSTOPBITS  0,1,2 = 1, 1.5, 2
public char XonChar;            // 指定用于发送和接收字符XON的值 Tx and Rx XON character
public char XoffChar;           // 指定用于发送和接收字符XOFF值 Tx and Rx XOFF character
public char ErrorChar;          // 本字符用来代替接收到的奇偶校验发生错误时的值 error replacement character
public char EofChar;            // 当没有使用二进制模式时,本字符可用来指示数据的结束 end of input character
public char EvtChar;            // 当接收到此字符时,会产生一个事件 received event character
public ushort wReserved1;         // 未使用 reserved; do not use
}

[StructLayout(LayoutKind.Sequential)]
private struct COMMTIMEOUTS {
public int ReadIntervalTimeout;
public int ReadTotalTimeoutMultiplier;
public int ReadTotalTimeoutConstant;
public int WriteTotalTimeoutMultiplier;
public int WriteTotalTimeoutConstant;
}

[StructLayout(LayoutKind.Sequential)]
private struct OVERLAPPED {
public int  Internal;
public int  InternalHigh;
public int  Offset;
public int  OffsetHigh;
public int hEvent;
}

[DllImport(“kernel32.dll”)]
private static extern int CreateFile(
string lpFileName,                         // 要打开的串口名称
uint dwDesiredAccess,                      // 指定串口的访问方式,一般设置为可读可写方式
int dwShareMode,                          // 指定串口的共享模式,串口不能共享,所以设置为0
int lpSecurityAttributes, // 设置串口的安全属性,WIN9X下不支持,应设为NULL
int dwCreationDisposition,                // 对于串口通信,创建方式只能为OPEN_EXISTING
int dwFlagsAndAttributes,                 // 指定串口属性与标志,设置为FILE_FLAG_OVERLAPPED(重叠I/O操作),指定串口以异步方式通信
int hTemplateFile                        // 对于串口通信必须设置为NULL
);
[DllImport(“kernel32.dll”)]
private static extern bool GetCommState(
int hFile,  //通信设备句柄
ref DCB lpDCB    // 设备控制块DCB
);
[DllImport(“kernel32.dll”)]
private static extern bool BuildCommDCB(
string lpDef,  // 设备控制字符串
ref DCB lpDCB     // 设备控制块
);
[DllImport(“kernel32.dll”)]
private static extern bool SetCommState(
int hFile,  // 通信设备句柄
ref DCB lpDCB    // 设备控制块
);
[DllImport(“kernel32.dll”)]
private static extern bool GetCommTimeouts(
int hFile,                  // 通信设备句柄 handle to comm device
ref COMMTIMEOUTS lpCommTimeouts  // 超时时间 time-out values
);
[DllImport(“kernel32.dll”)]
private static extern bool SetCommTimeouts(
int hFile,                  // 通信设备句柄 handle to comm device
ref COMMTIMEOUTS lpCommTimeouts  // 超时时间 time-out values
);
[DllImport(“kernel32.dll”)]
private static extern bool ReadFile(
int hFile,                // 通信设备句柄 handle to file
byte[] lpBuffer,             // 数据缓冲区 data buffer
int nNumberOfBytesToRead,  // 多少字节等待读取 number of bytes to read
ref int lpNumberOfBytesRead, // 读取多少字节 number of bytes read
ref OVERLAPPED lpOverlapped    // 溢出缓冲区 overlapped buffer
);
[DllImport(“kernel32.dll”)]
private static extern bool WriteFile(
int hFile,                    // 通信设备句柄 handle to file
byte[] lpBuffer,                // 数据缓冲区 data buffer
int nNumberOfBytesToWrite,     // 多少字节等待写入 number of bytes to write
ref int lpNumberOfBytesWritten,  // 已经写入多少字节 number of bytes written
ref OVERLAPPED lpOverlapped        // 溢出缓冲区 overlapped buffer
);
[DllImport(“kernel32.dll”)]
private static extern bool CloseHandle(
int hObject   // handle to object
);
[DllImport(“kernel32.dll”)]
private static extern uint GetLastError();

public void Open()
{

DCB dcbCommPort = new DCB();
COMMTIMEOUTS ctoCommPort = new COMMTIMEOUTS();

// 打开串口 OPEN THE COMM PORT.
hComm = CreateFile(PortNum ,GENERIC_READ | GENERIC_WRITE,0, 0,OPEN_EXISTING,0,0);
// 如果串口没有打开,就打开 IF THE PORT CANNOT BE OPENED, BAIL OUT.
if(hComm == INVALID_HANDLE_VALUE)
{
throw(new ApplicationException(“非法操作,不能打开串口!”));
}

// 设置通信超时时间 SET THE COMM TIMEOUTS.
GetCommTimeouts(hComm,ref ctoCommPort);
ctoCommPort.ReadTotalTimeoutConstant = ReadTimeout;
ctoCommPort.ReadTotalTimeoutMultiplier = 0;
ctoCommPort.WriteTotalTimeoutMultiplier = 0;
ctoCommPort.WriteTotalTimeoutConstant = 0;
SetCommTimeouts(hComm,ref ctoCommPort);

// 设置串口 SET BAUD RATE, PARITY, WORD SIZE, AND STOP BITS.
GetCommState(hComm, ref dcbCommPort);
dcbCommPort.BaudRate=BaudRate;
dcbCommPort.flags=0;
//dcb.fBinary=1;
dcbCommPort.flags|=1;
if (Parity>0)
{
//dcb.fParity=1
dcbCommPort.flags|=2;
}
dcbCommPort.Parity=Parity;
dcbCommPort.ByteSize=ByteSize;
dcbCommPort.StopBits=StopBits;
if (!SetCommState(hComm, ref dcbCommPort))
{
//uint ErrorNum=GetLastError();
throw(new ApplicationException(“非法操作,不能打开串口!”));
}
//unremark to see if setting took correctly
//DCB dcbCommPort2 = new DCB();
//GetCommState(hComm, ref dcbCommPort2);
Opened = true;
}

public void Close() {
if (hComm!=INVALID_HANDLE_VALUE) {
CloseHandle(hComm);
}
}

public byte[] Read(int NumBytes) {
byte[] BufBytes;
byte[] OutBytes;
BufBytes = new byte[NumBytes];
if (hComm!=INVALID_HANDLE_VALUE) {
OVERLAPPED ovlCommPort = new OVERLAPPED();
int BytesRead=0;
ReadFile(hComm,BufBytes,NumBytes,ref BytesRead,ref ovlCommPort);
OutBytes = new byte[BytesRead];
Array.Copy(BufBytes,OutBytes,BytesRead);
}
else {
throw(new ApplicationException(“串口未打开!”));
}
return OutBytes;
}

public void Write(byte[] WriteBytes) {
if (hComm!=INVALID_HANDLE_VALUE) {
OVERLAPPED ovlCommPort = new OVERLAPPED();
int BytesWritten = 0;
WriteFile(hComm,WriteBytes,WriteBytes.Length,ref BytesWritten,ref ovlCommPort);
}
else {
throw(new ApplicationException(“串口未打开!”));
}
}
}

class HexCon {
// 把十六进制字符串转换成字节型和把字节型转换成十六进制字符串 converter hex string to byte and byte to hex string
public static string ByteToString(byte[] InBytes) {
string StringOut=””;
foreach (byte InByte in InBytes) {
StringOut=StringOut + String.Format(“{0:X2} “,InByte);
}
return StringOut;
}
public static byte[] StringToByte(string InString) {
string[] ByteStrings;
ByteStrings = InString.Split(” “.ToCharArray());
byte[] ByteOut;
ByteOut = new byte[ByteStrings.Length-1];
for (int i = 0;i==ByteStrings.Length-1;i++) {
ByteOut[i] = Convert.ToByte((“0x” + ByteStrings[i]));
}
return ByteOut;
}
}
}

http://www.cnblogs.com/zhoufleru/archive/2007/06/04/770940.html

C# string 特殊的引用类型

.Net 框架程序设计(修订版)中有这样一段描述:String类型直接继承自Object,这使得它成为一个引用类型,也就是说线程上的堆栈上不会驻留有任何字符串。(译注:注意这里的“直接继承”。直接继承自Object的类型一定是引用类型,因为所有的值类型都继承自System.ValueType。值得指出的是System.ValueType却是一个引用类型)。

一:

 

string str1 = "string"; string str2 = "string";
Console.WriteLine(string.ReferenceEquals(str1, str2));

既然String类型是引用类型,那么代码一输出的应该是False,然而事实上代码一输出时的是True。

其实这是String类型的自动优化功能。str1,str2引用同一对象,节省内存,并不会为str2单独开辟内存空间。CLR使用了一种叫字符串驻留的技术,当CLR初始化时,会创建一个内部的散列表,其中的键为字符串,值为指向托管堆中字符串的引用。刚开始,散列表为空,JIT编译器编译方法时,会在散列表中查找每一个文本常量字符串,首先会查找”abc”字符串,并且因为没有找到,编译器会在托管堆中构造一个新的指向”abc”的String对象引用,然后将”abc”字符串和指向该对象的引用添加到散列表中。接着,在散列表中查找第二个”abc”,这一次由于找到了该字符串,指向同一个String对象的引用会被保存在变量str2中,到此str1和str2指向了同一个引用,所以string.ReferenceEquals(str1, str2)就会返回true了。

另外,C#中是不允许用new操作符创建String对象的,编译器会报错。

二:

 

static void Main(string[] args) {   string str = "string";
  Change(str);
  Console.WriteLine(str);
}
static void Change(string str) {
  str = "Changed";
}

方法传递的参数是原内容的拷贝,其过程如果用图可表示为:

 

语句str=”Changed”之前

语句str=”Changed”之后

这样可以看到原来String对象并未改变str=”Changed”只是创建一个新的String对象(其它引用类型是改变内存地址1指向的值),因此这个方法的参数需要加上ref或者out修饰符。因此这里也可以得出字符串具有恒等性,也就是说一个字符串一旦被创建,我们就不能再将其变长、变短、或者改变其中的任何字符。

MSDN上这样解释:字符串对象是不可变的,即它们一旦创建就无法更改。对字符串进行操作的方法实际上返回的是新的字符串对象。

string在另一种情况下的操作是具有值类型特征的:str1 == str2 ,仅仅是比较了值,而非地址(是MS重写了==运算符所致).

 

三:

String 对象是不可改变的。每次使用 System.String 类中的方法之一时,都要在内存中创建一个新的字符串对象,这就需要为该新对象分配新的空间。在需要对字符串执行重复修改的情况下,与创建新的 String 对象相关的系统开销可能会非常昂贵。如果要修改字符串而不创建新的对象,则可以使用 System.Text.StringBuilder 类。例如,当在一个循环中将许多字符串连接在一起时,使用 StringBuilder 类可以提升性能。

下面看一个极简单的例子:

 

namespace TCP { public class Program {
     public class User       {           private string _name;           private string _age;           public User(string name, string age)           {               _name = name;               _age = age;           }           public string name           {               get { return _name; }               set { _name = value; }           }           public string age           {               get { return _age; }               set { _age = value; }           }       }
   }
   public static void editUser(User user, StringBuilder str,string code)    {      code = "VB.NET";      str = str.Remove(0, 1);      str.Append("E");      user.name = "LEE"; user.age = "10"; }
static void Main(string[] args)    {      string code = "C#";    User user = new User("Li","23");      StringBuilder str = new StringBuilder();                  str.Append("A");                  editUser(user, str,code);      Console.WriteLine(code);      Console.WriteLine(str);      Console.WriteLine(user.name);      Console.WriteLine(user.age);      Console.ReadLine();    }
}

 

上面代码输如下:

这样可以看到原来String对象并未改变str=”Changed”只是创建一个新的String对象(其它引用类型是改变内存地址1指向的值),因此这个方法的参数需要加上ref或者out修饰符。因此这里也可以得出字符串具有恒等性,也就是说一个字符串一旦被创建,我们就不能再将其变长、变短、或者改变其中的任何字符。

MSDN上这样解释:字符串对象是不可变的,即它们一旦创建就无法更改。对字符串进行操作的方法实际上返回的是新的字符串对象。

string在另一种情况下的操作是具有值类型特征的:str1 == str2 ,仅仅是比较了值,而非地址(是MS重写了==运算符所致).

 

三:

String 对象是不可改变的。每次使用 System.String 类中的方法之一时,都要在内存中创建一个新的字符串对象,这就需要为该新对象分配新的空间。在需要对字符串执行重复修改的情况下,与创建新的 String 对象相关的系统开销可能会非常昂贵。如果要修改字符串而不创建新的对象,则可以使用 System.Text.StringBuilder 类。例如,当在一个循环中将许多字符串连接在一起时,使用 StringBuilder 类可以提升性能。

下面看一个极简单的例子:

 

namespace TCP { public class Program {
     public class User       {           private string _name;           private string _age;           public User(string name, string age)           {               _name = name;               _age = age;           }           public string name           {               get { return _name; }               set { _name = value; }           }           public string age           {               get { return _age; }               set { _age = value; }           }       }
   }
   public static void editUser(User user, StringBuilder str,string code)    {      code = "VB.NET";      str = str.Remove(0, 1);      str.Append("E");      user.name = "LEE"; user.age = "10"; }
static void Main(string[] args)    {      string code = "C#";    User user = new User("Li","23");      StringBuilder str = new StringBuilder();                  str.Append("A");                  editUser(user, str,code);      Console.WriteLine(code);      Console.WriteLine(str);      Console.WriteLine(user.name);      Console.WriteLine(user.age);      Console.ReadLine();    }
}

 

上面代码输如下:

 

从上面可以看到string类型的值并没有改变,StringBuilder与class的值都改变了。

http://www.cnblogs.com/justForMe/archive/2010/09/09/1822203.html