C#(C Sharp发音为“C霎普”)牢固地植根于C和C++语言族谱中,并且会很快被C和C++程序员所熟悉。
C#的目标在于把Visual Basic的高生产力和C++本身的能力结合起来。
C#作为Microsoft Visual Studio 7.0的一部分提供给用户。
除了C#以外,Visual Studio还支持Visual Basic、Visual C++和描述语言VBScript和Jscript。
所有这些语言都提供对Microsoft .NET平台的访问能力,它包括一个通用的执行引擎和一个丰富的类库。
Microsoft .NET平台定义了一个“通用语言子集”(CLS),是一种混合语言,它可以增强CLS兼容语言和类库间的无缝协同工作能力。
对于C#开发者,这意味着既是C#是一种新的语言,它已经可以对用老牌工具如Visual Basic和Visual C++使用的丰富类库进行完全访问。C#自己并没有包含一个类库。
本章的其余部分描述这种语言的基本特性。
规范的“Hello,World”程序可以按照下面例子编写:
using System;
class Hello
{
static void Main() {
Console.WriteLine("Hello, world");
}
}
C#程序的源代通常存储在一个或多个扩展名为.cs的文件中,例如hello.cs。如果使用Visual Studio提供的命令行编译器,这样的程序可以用命令行命令来编译
csc hello.cs
这样就会生成一个名为hello.exe的可执行程序。程序的输出如下:
Hello, world
下面对这个程序进行详细的研究:
· 使用System;指令涉及到一个名称空间(namespace)叫作System,这是在Microsoft .NET类库中提供的。这个名称空间包括在Mian方法中使用的Console类。名称空间提供了一种用来组织一个类库的分层方法。使用“using”命令后,就可以无障碍地使用名称空间中的各种类型成员。“Hello,world”程序中使用的Console.WriteLine是System.Console.WriteLine的简写。
· Main方法是类Hello中的一个成员,它有static的说明符,所以它是类Hello中的一个方法而不是此类中的实例。
· 对于一个应用程序的主入口点-称开始执行的方法-通常是一个称为Main的静态方法。
· “Hello,world”的输出是通过使用类库产生的。语言本身并没有提供类库。作为替代,它使用一个通用类库,这个类库也可以被诸如Visual Basic和Visual C++的语言所使用。
对于C和C++开发者来说,会有兴趣知道对一些没有出现在“Hello,world”程序的东西。
· 程序没有把Main设为全局方法。在全局级别上不支持方法和变量;这些元素通常包含在类型声明当中(例如,类或结构的声明)。
· 程序中不使用“::”或“->”操作符。“::”不再是一个操作符,而“->”操作符也只是在程序的某个小片断中才会使用。操作符“.”用于符合名称,例如Console.WriteLine。
· 程序中不包括前向声明。因为声明的顺序不重要,所以不再需要前向声明。
· 程序中不使用#include关键字。程序中的从属关系是象征性的而不是字面上地。这个系统消除了在用不同语言编写的程序间的障碍。例如,Console类可以用另外一种语言编写。
运行环境:
IBM T30
CPU:1.8GHZ
内存:256M
硬盘:40G
OS:Windows Server 2000 SP4
Visual Studio .NET 2003(Framework v1.1.4322)
Microsoft SQL Server 2000
机器配置跑不动 VS2005,很是郁闷,故本次旅行仅限制在Framework v1.1.4322。
废话少说,第一个例子,使用记事本编写C#语句输出XML文件。
第一步:打开记事本,输入以下代码。
// 文件test001.cs
using System;
using System.Xml;
public class Hello51CTO {
public static void Main(string [ ] args) {
XmlTextWriter writer = new XmlTextWriter(Console.Out);
writer.WriteStartDocument( );
writer.WriteElementString("网址", "http://c.blog.51cto.com/");
writer.WriteEndDocument( );
writer.Close( );
}
}
// 文件test001.cs结束
第二步:打开一个DOS窗口(运行,CMD,回车),我们使用如下命令行编译test001.cs
C:WINNTMicrosoft.NETFrameworkv1.1.4322csc /debug /target:exe test001.cs
// csc是C#的编译器,生成一个同名的exe文件test001.exe
// 参数/debug 是让编译器生成一个包含调试信息的附加文件test001.pdb
第三步:如果编译成功,则会生成两个文件test001.exe和test001.pdb,我们在DOS窗口下输入test001,运行刚刚生成的文件,可以看到输出如下内容:
<?xml version="1.0" encoding="gb2312"?><网址>http://c.blog.51cto.com/</网址>
怎么样,我们用记事本输出了一个简单的XML文件。
1.1、例外的情况是,对于IDE无法辨认的属性的解析。
比如对一个RadioButton rbt,IDE不能辨认onclick这个属性,那么,类似上面的语句,
rbt.Attributes.Add("onclick", "fcn1(this);");
在.net framework 1.1中,将解析成
<input type=radio id=rbt onclick="fcn1(this);">...
而在在.net framework 1.0中,将解析成
<span onclick="fcn1(this);"><input type=radio id=rbt>...</span>
注意到,fcn1中,参数this对应的对象就不同了。这是一个细微的差别。
2、而对于HTML control,需要多做一点事情。
在设计aspx页面的时候,从工具栏拖一个web form control,比如说,TextBox到页面,会发生两件事:
一、aspx页面多一句
<asp:TextBox id="TextBox1" style="..." runat="server" Width="102px" Height="25px"></asp:TextBox>
二、code behind多一句
protected System.Web.UI.WebControls.TextBox TextBox1;
如果是html control,那么,第一句中,runat="server"不会出现,而第二局不会被自动添加。
因此,如果要访问html control,需要
一、aspx页面的语句中添加runat="server"属性,成为
<INPUT style="..." type="text" size="9" id="htxt" runat="server">
二、code behind中显示的声明
protected System.Web.UI.HtmlControls.HtmlInputText htxt;
注意到第一句的id和第二句的变量名是相同的。
2.1、注意到,前面System.Web.UI.WebControls.TextBox对应的html control是System.Web.UI.HtmlControls.HtmlInputText,对应的html的tag是<INPUT type="text">,
相应的,html的tag <body>对应的html control是
public System.Web.UI.HtmlControls.HtmlGenericControl myBody;
2.2、有一点例外的是html的<form> tag对应的onsubmit的事件。看这样一个aspx页面
<%@ Page language="c#" Codebehind="WebForm2.aspx.cs" AutoEventWireup="false" Inherits="TestCs.WebForm2" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
<HTML>
<HEAD>
<title>WebForm2</title>
<meta name="GENERATOR" Content="Microsoft Visual Studio 7.0">
<meta name="CODE_LANGUAGE" Content="C#">
<meta name="vs_defaultClientScript" content="JavaScript">
<meta name="vs_targetSchema" content="http://schemas.microsoft.com/intellisense/ie5">
<script language="javascript">
function fcn1()
{
prompt("hi", "fcn1");
}
</script>
</HEAD>
<body MS_POSITIONING="GridLayout">
<form id="WebForm2" method="post" runat="server" onsubmit="fcn1();">
<asp:Button id="Button1" style="Z-INDEX: 103; LEFT: 423px; POSITION: absolute; TOP: 83px" runat="server" Width="86px" Height="29px" Text="Button"></asp:Button>
<asp:DropDownList id="DropDownList1" style="Z-INDEX: 104; LEFT: 284px; POSITION: absolute; TOP: 163px" runat="server" Width="188px" Height="17px" AutoPostBack="True">
<asp:ListItem Value="a">a</asp:ListItem>
<asp:ListItem Value="b">b</asp:ListItem>
<asp:ListItem Value="c">c</asp:ListItem>
</asp:DropDownList>
</form>
</body>
</HTML>
内容很简单,定义了一个javascript函数fcn1,放了一个Button Button1和一个autopostback的Dropdownlist DropDownList1,运行它,可以看到:点击Button1,会先执行fcn1然后postback,而选择DropDownList1的不同选项,将只会postback,而不会触发fcn1。
微软autopostback=true的webcontrol实现postback,原理是这样的:
一、如果此aspx页面有autopostback=true的webcontrol,那么会写下面一段javascript语句定义一个叫__doPostBack的javascript函数。
<script language="javascript">
<!--
function __doPostBack(eventTarget, eventArgument) {
var theform;
if (window.navigator.appName.toLowerCase().indexOf("netscape") > -1) {
theform = document.forms["WebForm2"];
}
else {
theform = document.WebForm2;
}
theform.__EVENTTARGET.value = eventTarget.split("$").join(":");
theform.__EVENTARGUMENT.value = eventArgument;
theform.submit();
}
// -->
</script>
二、例如是上面的dropdownlist,将会render成:
<select name="DropDownList1" onchange="__doPostBack('DropDownList1','')" language="javascript" id="DropDownList1" style="...">
<option value="a">a</option>
<option value="b">b</option>
<option value="c">c</option>
</select>
这样,通过javscript调用theform.submit();来submit form,postback,但是,theform.submit将不会触发form的onsubmit事件!
这是微软的一个bug。
解决的方法可以看这里:http://www.devhawk.net/art_submitfirefixup.ashx,这里提供了一个dll及源代码,使用的时候,在project的reference里加入这个dll,然后在web.config中加上一段
<httpModules>
<add type="DevHawk.Web.SubmitFireFixupModule,SubmitFireFixupModule" name="SubmitFireFixupModule" />
</httpModules>
就可以了。
3、一个应用。
常常听到抱怨,说如果在Browser端用javascript改动了某个<select>元素,那么,它对应的Server端的DropDownList不能得知这个更新。
这种情况可能出现在“级联”的DropDownList中,比如第一个DropDownList是省份,第二个是城市;也可能出现在,从第一个DropDownList选择某些项加入到第二个DropDownList中。
对此使用以上的技术,我做了一个这样的解决方案(类似于ViewState的方法):
一、我定义了一个长宽都是0的TextBox txtWrap,并把所有我想处理的DropDownList都加上AthosOsw="True" 这样的属性,准备处理。
二、参照上面2.2的内容,我加入了SubmitFireFixupModule,来保证触发form的onsubmit事件。
三、form的onsubmit事件将执行javascript函数fcnAthosOnSubmitWrap,它将遍历AthosOsw属性为True的DropDownList,记下数据,最后合并起来放到txtWrap里,其实这就是一个序列化的过程。代码如下:
function fcnAthosOnSubmitWrap()
{
txtWrap = document.all["txtWrap"];
var i;
var strWrap = '';
for(i=0;i<document.all.length;i++)
{
ctrl = document.all[i];
if(ctrl.tagName.toUpperCase() == 'SELECT' && typeof(ctrl.AthosOsw) != 'undefined' )
{
if(ctrl.AthosOsw.toUpperCase() == 'TRUE')
{
strWrap += fcnAthosWrapSelect(ctrl) + '&&&';
}
}
}
if(strWrap.length>3)
txtWrap.value = strWrap.substring(0, strWrap.length-3);
};
//AthosOsw
function fcnAthosWrapSelect(ctrlSelect)
{
var i;
var strWrapSelect = ctrlSelect.id + '&' + ctrlSelect.tagName;
var strValue='';
var strText='';
for(i=0; i<ctrlSelect.options.length; i++)
{
strValue = ctrlSelect.options[i].value;
strText = ctrlSelect.options[i].text;
strWrapSelect += '&&' + i + '&' + strValue.replace(/&/g, '%26') + '&' + strText.replace(/&/g, '%26');
};
return strWrapSelect;
};
四、form的Page_Load中调用clsCommon.UnwrapControl(this, txtWrap.Text);来反序列化。clsCommon是我的工具类,UnwrapControl方法代码如下:
static public void UnwrapControl(System.Web.UI.Page pgUnwrap, String strUnwrap)
{
Regex r3 = new Regex("(&&&)"); // Split on hyphens.
Regex r2 = new Regex("(&&)"); // Split on hyphens.
Regex r1 = new Regex("(&)"); // Split on hyphens.
String[] sa3, sa2, sa1;
String s3, s2, s1;
int i3, i2, i1;
String strId, strTagName;
System.Web.UI.Control ctrlUnwrap;
DropDownList ddlUnwrap;
ListItem liAdd;
s3 = strUnwrap;
sa3 = r3.Split(s3);
for(i3=0;i3<(sa3.Length+1)/2;i3++)
{
s2 = sa3[i3*2];
if(s2.Length>0)
{
sa2 = r2.Split(s2);
if(sa2.Length>1)
{
s1 = sa2[0];
sa1 = r1.Split(s1);
if(sa1.Length==3)
{
strId = sa1[0];
strTagName = sa1[2];
ctrlUnwrap = pgUnwrap.FindControl(strId);
if(ctrlUnwrap !=null)
{
if(strTagName == "SELECT")
{
ddlUnwrap = (DropDownList)ctrlUnwrap;
ddlUnwrap.Items.Clear();
for(i2=1; i2 < (sa2.Length+1)/2;i2++)
{
s1 = sa2[i2*2];
sa1 = r1.Split(s1);
liAdd = new System.Web.UI.WebControls.ListItem(sa1[4],sa1[2]);
ddlUnwrap.Items.Add(liAdd);
}
}
}
}
}
}
}
}
请点击下载种子
http://c.blog.51cto.com/get/325/vs2005.rar
cs_vs_2005_pro_dvd.iso.torrent
Visual Studio 2005 Professional Edition - DVD - (Simplified Chinese)
cs_vs_2005_vsts_trial_dvd.iso.torrent
Visual Studio 2005 Team Suite Trial Edition - DVD - (For Evaluation Only) (Simplified Chinese)
cs_vwd_2005_express.iso.torrent
Visual Web Developer 2005 Express Edition (Simplified Chinese)
cs_msdn_vs_2005_dvd.iso.torrent
MSDN Library for Visual Studio 2005 - DVD (Simplified Chinese)
cs_visio_enterprise_architects_2005.iso.torrent
Visio for Enterprise Architects (Visual Studio 2005) (Simplified Chinese)
en_sql_2005_ent_x86_dvd.iso.torrent
SQL Server 2005 Enterprise Edition - 32-bit - DVD (English)
注:VS2005是180day试用版,但添加注册码升级到正式版,然后点升级就OK了!
SN:KYTYH-TQKW6-VWPBQ-DKC8F-HWC4J
我经常听到有人问这个问题:“在ASP.NET Web应用程序中我应该用DataReader类还是DataSet类呢?”在很多文章以及新闻组的贴子中我经常看到这样的误解,即认为DataReader(SqlDataReader或OleDbDataReader的缩写)比DataSet好。有时候我也会看到相反的说法。事实上,Microsoft创建了这两个数据存取类是因为它们都是我们所需要的。每个类都有其优点和不足,你可以根据应用环境来选择用哪一个。
本文就两者的选择问题做了很清楚的讲述,可以让你在运用ASP.NET时,在选择DataReader类或DataSet类的方面得到一些指南。在基于客户端的Windows Form应用程序环境下,这些规则可能会改变。我在做这些讲述时,假设你已经用过DataReader和DataSet类了,并对它们很熟悉。
运用DataReader类
下面就是运用DataReader类的理想条件: 你读取的数据必须是新的,所以在每次需要数据的时候,你都必须从数据库读取。创建一个DataReader类不会消耗很多内存,不过随着负荷的增加,DataSet上的性能也会很快地提高(参考资源中Visual Studio Magazine中的文章)。
你对每行数据的需求很简单。该情况的最好的例子就是简单地将DataReader绑定到一个Web控件,如DataGrid或DropDownList。
你只需要从数据库中以只向前的(forward-only) 、只读的形式来存取XML数据。在这种情况下,你可以用SQLCommand对象的ExcecuteXmlReader()方法来得到一个XmlReader类(相当于XML版的DataReader)。这就需要一个运用FOR XML子句的SQL Server查询,或者一个包含有效XML的ntext字段。
你计划对数据库进行几个重复的调用,来读取一小块信息。在这种情况下,我们前面提到过的性能数据会有更大的提高。
的确,使DataSet类更强大的许多功能只适用于基于客户端的Windows Form应用程序,比如在多个表之间建立关系的功能。在很多情况下,DataSet类都比DataReader类更有优势,而且在有些情况下,你根本就不能用DataReader类。
运用DataSet类
在下面的情况,你应该考虑运用DataSet类: 你构建了一个Web service,它运用的数据是你作为返回值读取的数据。因为DataReader类必须保持到数据库的连接,所以它们不能被序列化到XML中,也不能被发送给一个Web service的调用者。
你需要排序或筛选数据。在运用一个DataView对象(呈现为DataTable类的DefaultView属性,它包含一个DataSet类)来排序或筛选数据前,我们先试着用SQL查询(如WHERE和ORDER BY语句)来实现这些功能,并运用更轻量级、更快的DataReader类。然而,有时侯用这种方法是不行的,或者当你需要多次地对数据进行排序或筛选时就不能用DataReader。
针对同一请求,你需要多次遍历数据。你只能在DataReader中循环一次。如果你想将多个ServerControl类绑定到同一个数据集,那么选择DataSet就更好。DataReader类不能被绑定到多个ServerControl类,因为它是只向前读取的。在这种情况下,如果要使用DataReader,必须从数据库读取两次数据。
你需要存储数据,而后续的页面请求可能会用到的这些数据。如果数据只被请求它的专门的人使用,你可以将DataSet类保存在一个Session变量中。如果数据可以被任何人访问,那么你可以将它保存在一个Application变量中,或保存在Cache中(我建议使用后一种方法,因为它支持时间期限和回调(callback))。因为DataReader类必须一直打开对数据库的连接,而且它一次只能保存一行数据,所以它们不能在跨页面请求中被保存。
你需要对一个结果集的每个元素实现特殊的、耗时的功能。例如,如果你从一个数据库读取一列邮政编码,并想通过调用一个Web service来得到每个地区的详细的天气状况信息,那么选择DataSet就会更好。这是因为,当你在用DataReader类时,在关闭DataReader类前,与数据库的连接不会被释放回连接池。在数千页面请求之间潜在的一个很小的延时都会造成Web应用程序的很高的访问量,从而就会消耗完可用的连接。相反,DataSet可以在前端读取所有的数据,并可以马上关闭与数据库的连接,将它返回到连接池,因此其它的页面请求就可以用这个连接了。
你需要在一个两维范例中加载并处理XML数据。DataSet类对于XML很有用,因为你可以将DataView用于XML,对根本的数据进行排序和筛选,就同处理一个数据库结果集一样。然而,需要注意的是在System.Xml名字空间中有很多类,你可以将它们用于更复杂的XML操作。
你的数据源不是一个数据库。虽然OleDbDataReader可以用于任何OLEDB数据提供者(可能指向一个数据库,也可能不指向一个数据库),但DataSet对象可以从一个XML文件直接加载数据,并动态地解释它的schema。DataSet类也可以将XML数据写回一个数据流或一个文件。
从上面的讲述我们就可以看到,DataSet类比DataReader类有更多的功能,这就可以让你在更多的情况下运用它们。但这并不意味着你总是在用DataSet类。你需要在ASP.NET中完成的相当大一部分的任务都属于DataReader的范畴。
尽管如此,毫无疑问,从重要程度或复杂程度的角度来说,DataSet类在很多ASP.NET Web应用程序中都起着很重要的作用。你可以通过明智的缓存来最小化数据库往返,从而降低DataSet类的“性能损害”。DataReader和DataSet都是一个成功的ASP.NET Web应用程序的重要的部件。重要的是,我们需要了解何时、在哪里可以最好的使用它们。
WMI 是 Windows Management Instrumentation 。
/// <summary>
/// 获取磁盘信息
/// </summary>
/// <returns></returns>
public string getdisk()
{
// disk["DriveType"] 的返回值意义如下:
// 1 No type
// 2 Floppy disk
// 3 Hard disk
// 4 Removable drive or network drive
// 5 CD-ROM
// 6 RAM disk
string a="";
SelectQuery query=new SelectQuery("Select * From Win32_LogicalDisk");
ManagementObjectSearcher searcher=new ManagementObjectSearcher(query);
foreach(ManagementBaseObject disk in searcher.Get())
{
a += (" "+disk["Name"] +" "+disk["DriveType"] + " " + disk["VolumeName"]) + diskinfo(disk["Name"].ToString()) +"n";
}
return a;
}
/// <summary>
/// 获取磁盘大小
/// </summary>
/// <param name="d"></param>
/// <returns></returns>
public string diskinfo(string d)
{
string a="";
ManagementObject disk = new ManagementObject("win32_logicaldisk.deviceid='"+d+"'");
disk.Get();
a = (" " + disk["Size"] + " bytes");
return a;
}
/// <summary>
/// 获取网卡地址
/// </summary>
/// <returns></returns>
public string getmacaddress()
{
string a="";
ManagementClass mc = new ManagementClass("Win32_NetworkAdapterConfiguration");
ManagementObjectCollection moc = mc.GetInstances();
foreach(ManagementObject mo in moc)
{
if((bool)mo["IPEnabled"] == true)
a = "网卡:" + mo["MacAddress"].ToString() + "n";
mo.Dispose();
}
return a;
}
/// <summary>
/// 获取CPU信息
/// </summary>
/// <returns></returns>
public string cpuinfo()
{
string a="";
ManagementClass mcobject = new ManagementClass("Win32_Processor");
ManagementObjectCollection moc = mcobject.GetInstances();
foreach(ManagementObject mo in moc)
{
a += "CPU:" + mo.Properties["ProcessorId"].Value.ToString() + "n";
}
return a;
}
/// <summary>
/// 获取硬盘型号
/// </summary>
/// <returns></returns>
public string hardinfo()
{
string a="";
ManagementClass mcobject = new ManagementClass("Win32_DiskDrive");
ManagementObjectCollection moc = mcobject.GetInstances();
foreach(ManagementObject mo in moc)
{
a += "硬盘型号:" + mo.Properties["Model"].Value.ToString() + mo.Properties[""].Value.ToString() + "n";
}
return a;
}
public string baseboard()
{
string a="";
SelectQuery query=new SelectQuery("SELECT * FROM Win32_BaseBoard");
ManagementObjectSearcher searcher=new ManagementObjectSearcher(query);
foreach(ManagementBaseObject disk in searcher.Get())
{
a += "主板制造商: "+disk["Manufacturer"] +"n型号: "+disk["Product"] + "n序列号: " + disk["SerialNumber"] +baseinfo() +"n";
}
return a;
}
public string baseinfo()
{
string a="";
SelectQuery query=new SelectQuery("Select SerialNumber From Win32_BIOS");
ManagementObjectSearcher searcher=new ManagementObjectSearcher(query);
foreach(ManagementBaseObject disk in searcher.Get())
{
a = disk["SerialNumber"].ToString();
}
return a;
}
参考资料
msdn WMI SDK:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wmisdk/wmi/wmi_reference.asp