.NET框架以及在C++中的初步应用
在最新发布的Visual Studio.NET中,随带一种新的技术叫.NET框架。这是一种新的编程机制,微软旨在编程时,提供一个统一的面向对象环境,而且保证对象的透明性(即无论这个对象是否是在本机,Internet上,还是在某个远程环境中);使得在各种软件中的版本冲突达到最小;使得对象达到语言无关性,能够跨语言调用。在.NET框架中,有很大一部分的特性十分类似于JAVA,如:内存管理,类库引用,类似于字节码的MSIL代码等等。
为了充分使用.NET框架,于是微软推出C#.NET这个语言版本。我将使用C#来看一看.NET框架机制。先看一个完整的C#程序:
001:using System;
002:using System.Drawing;
003:using System.Windows.Forms;
004:
005:
007:
008:class Sample
009: {
010: Sample()
011: {
012: m_nMember = 0;
013: }
014:
015: ~Sample()
016: {
017: System.Console.WriteLine ("我被释放掉了.");
018: }
019:
020: delegate void MethodDge (string strMessage);
021:
022: public int Member
023: {
024: set
025: {
026: m_nMember = value;
027: System.Console.WriteLine ("被赋值了。");
028: }
029: get
030: {
031: System.Console.WriteLine ("被取值了。");
032: return m_nMember;
033: }
034: }
035:
036: public void Click(Object sender, EventArgs e)
037: {
038: System.Console.WriteLine ("被单击了!{"};
039: this.Member = 13;
040: System.Console.WriteLine (Member.ToString()+")");
041: }
042:
043: public void OwnMethod (string strMessage)
044: {
045: System.Console.WriteLine (strMessage);
046: }
047:
048: public int m_nMember;
049:
050: public static void Main()
051: {
052: Sample aSample = new Sample();
053: Form Dlg = new Form();
054: EventHandler Click = new EventHandler (aSample.Click);
055: Dlg.Text = "这是一个.NET窗体";
056: Dlg.Click += Click;
057: Dlg.ShowDialog (null);
058: MethodDge InokeMethod = new MethodDge (aSample.OwnMethod);
059: InokeMethod ("这是由委托调用。"+InokeMethod.ToString());
060: }
061: }
这段程序基本上涵盖了.NET大部分特性特性。基本上是很容易看懂的,下面简单讲讲.NET的特性,请对照着例子来看。
.NET类库引用
首先,在Java中是使用import来引用类库的,而C#是使用using,C++使用#using来进行导入类库。并且这些类库都是些被封装在.dll文件中的MSIL代码,叫Microsoft中间语言代码。这些MSIL代码是由.NET 框架实时 (JIT) 编译器来进行编译成本机代码执行的,有点像Java中的解释器解释字节码。我们所编写托管代码(即.NET程序代码)会被编译器编译成MSIL代码,然后由链接器按照PE格式写入.exe或.dll文件当中去。当系统执行文件遇到MSIL时,会使用.NET 框架实时编译器将实时MSIL编译成本机代码,再去执行本机代码。
.NET内存回收
在Java中有一种垃圾回收机制,可以将失去引用的对象自动的释放掉。.NET框架的公共语言运行库也包含了这一功能,我们可以在new完对象以后,无需操心什么时候去delete事了,公共语言运行库会知道什么时候去释放它,且不会影响资源使用效率,也许会有所提高呢。在例子中的主函数里,aSample引用了一个被new出来的Sample对象。在主函数结束时,aSample失去了作用,公共语言运行库当发觉到new出来的那个对象没有人再去引用它,便就立即将它析构了。于是,在主函数结束处,Sample的析构函数被执行了。
.NET类型
1.Object类型
再说说类型,在.NET中,所有类型(包括int,float,double等等)都是派生于Object类的,所以一个Object变量可以被赋与任何类型的值。由于,Object中有关于类型的描述,所以不用担心Object中的类型不明确。如:
int a = 13;
Object b = a;
System.Console.WriteLine (b);
WriteLine会知道b中的值是整型,它的输出仍然是13。
2.值类型与引用类型
在.NET中,类型被分为值类型和引用类型两种(在JAVA同样存在),引用类型行为相当于C\C++中的指针,这种类型包括类类型(用关键字class声明的类型),接口类型(用关键字interface声明的类型),数组类型,委托类型(用关键字delegate声明的类型)。值类型与引用类型的区别示例如下:
class MyClass
{
int a;
}
class Example
{
static void Main (string [] args)
{
int value1 = 12;
int value2 = value1;
MyClass citation1 = new MyClass();
MyClass citation2 = citation1;
value1 = 13;
value2 = 15;
citation1.a = 13;
citation2.a = 15
System.Console.WriteLine (value1.ToSting()+”,”+value2.ToSting());
System.Console.WriteLine (citation1.a.ToString()+”,”+citation2.a.ToString());
}
}
其结果为
13,15
15,15
当一个值类型赋给另一个值类型时,int value2 = value1;是将value1的值复制到value2里去。因此实际存在着两个整型变量。所以当value2值改变时,不会影响到value1的值。而一个引用类型赋给另一个引用类型时,MyClass citation2 = citation1;是将citation2引用成citation1所引用的对象,因此实际只存在一个MyClass对象。citation1和citation2同时指向一个对象,所以当改变citation2.a,citation1.a也同时改变,它们两个是同一个对象。这就是引用类型和值类型的区别,这是.NET中一个比较重要的概念。不过,这在C\C++中关系不大,因为.NET在C++中是用指针来达到引用的概念的(虽然C++中有自己的引用语法),我们仍然可以不使用指针,将类当成值类型来用。
如在C++中的Object __gc * Target相当于C#中的Object Target;
[C#]
Object Target = new Object();
Target.ToString();
[C++]
Object __gc * Target = new Object();
Target->ToString();
两者是等效的。
在C++中__gc表示为托管类型(即.NET类型)。
3.委托类型
在.NET中,委托的行为与C\C++的函数指针相同。如第一个例子中的EventHandler, MethodDge都是委托类型。不同的是,MethodDge是我们自己定义的委托类型,EventHandler是系统程序集定义的委托类型。一个委托类型是这么声明的:
[C#]
delegate 返回值 类型名 (参数列表);
[C++]
__delegate 返回值 类型名 (参数列表);
请看示例的第20行。
一个委托对象是这么声明的:
[C#]
委托类型名 委托对象名 = new (对象.方法)
[C++]
委托类型名 * 委托对象名 = new (对象指针,&(类::方法))
请看示例的第54行和第58行。
当调用委托对象,就等同于调用被引用的函数
[C# & C++]
委托对象名(参数列表);
请看示例的第59行。
而且委托类型支持累加(+=)与累减(-=),当调用委托对象时,效果是累加起来所有委托对象的同时被调用;
[C# & C++]
委托对象名 += 委托类型对象名;
委托对象名 -= 委托类型对象名;
请看示例的第56行。
委托对象主要用在事件上。事件,在Java是利用接口来实现的,.NET框架是由委托对象来实现的。在每个有事件的类中都有几个事件委托对象(EventHanlder类型的,其中有两个参数是Object sender,EventArgs e)的属性与之事件相对应。如有支持单击事件则,该类就肯定有一个名为Click的委托对象属性。当类对象有单击事件产生,则就调用这个委托对象:
if (Click != null)
Click (this, e);
如果想要订阅这份事件,则可以累加上自己的委托对象,取消订阅则累减去自己的委托对象。
第一个例子中的
.NET的类中
1.属性
在第一个例子中,类Sample有一个Member成员的声明。这是一个属性的声明。当Member被取值时调用get程序块返回一个整型值;当Member被赋值时调用set程序块,在C#中参数被隐式声明为value。
在C++中是用__property来声明的
[C++]
__property 类型 get_属性名();//赋值器
__property void set_属性名(类型 value);//取值器
请看示例的第22到34行。
2.不能实例化的类
使用关键字abstract来显示声明这个类为抽象类,不管它是否有纯虚函数。当类被声明为抽象类后,它就不允许实例化出类对象。声明方法如下:
[C#]
abstract class 类名
{
....
}
[C++]
__abstract __gc class 类名
{
...
};
在C++中__gc表示为托管类型(即.NET类型),__nogc显示声明类为非托管类型(即普通的C++类)
3.不能当做基类的类
使用关键字sealed可将类显示声明为封装类。当类被声明为封装类后,不允许有任何类以它为基类。声明方法如下:
[C#]
sealed class 类名
{
....
}
[C++]
__sealed __gc class 类名
{
...
};
以上就是.NET行为上的特性,下面将第一个例子翻成C++托管程序代码,功能效果与C#程序相同:
#using <mscorlib.dll>
#using <System.dll>
#using <System.Drawing.dll>
#using <System.Windows.Forms.dll>
using namespace System;
using namespace System::Windows::Forms;
__gc class Sample
{
public:
Sample(void)
{
m_nMember = 0;
}
~Sample(void)
{
System::Console::WriteLine ("我被释放掉了.");
}
__delegate void MethodDge (String * strMessage);
__property void set_Member (int nValue)
{
m_nMember = nValue;
System::Console::WriteLine ("被赋值了。");
}
__property int get_Member (void)
{
System::Console::WriteLine ("被取值了。");
return m_nMember;
}
void Click(Object * sender, EventArgs * e)
{
System::Console::WriteLine ("被单击了!");
System::Console::WriteLine ("{");
Member = 13;
System::Console::WriteLine (Member.ToString());
System::Console::WriteLine ("}");
}
void OwnMethod (String * strMessage)
{
System::Console::WriteLine (strMessage);
}
int m_nMember;
};
void main ()
{
Sample * aSample = new Sample();
Form * Dlg = new Form();
EventHandler * Click = new EventHandler (aSample,Sample::Click);
Dlg->Text = "这是一个.NET窗体";
Dlg->Click += Click;
Dlg->ShowDialog (0);
Sample::MethodDge * InokeMethod = new Sample::MethodDge (aSample,Sample::OwnMethod);
InokeMethod (String::Concat ("这是由委托调用。",InokeMethod->ToString()));
}
第一行的#using <mscorlib.dll>是公共运行库.
若要在Visual C++.NET上编译通过,请先将项目属性页上的C\C++中常规里的编译为托管设置成为程序集支持。
具体类库应用请查看MSDN.NET上的.NET框架.(.NET框架->参考->类库)
C++的扩展托管请查看MSDN.NET上的Visual C++.NET.( Visual C++.NET->C++ 托管扩展编程)
释雪
2002.11.30