
[c-sharp] view plaincopy
using System
using System.Diagnostics
using System.IO
using System.Reflection
namespace InvokeMember
{
///
/// Class1 的摘要说明。
///
class Class1 { ///
/// 应用程序的主入口点。
///
[STAThread]
static void Main(string[] args)
{
//循环次数
const int iterations = 100
//计算所用时间
DateTime startTime = DateTime.Now
for(int i = 0i<iterationsi++) { //对照方法
Console.WriteLine("Hello,World")
}
TimeSpan elasped = DateTime.Now - startTime
Console.WriteLine("Looping Elapsed milliseconds:" + elasped.TotalMilliseconds + "for {0} iterations",iterations)
//使用反射发送
ReflectionTest t = new ReflectionTest()
//计算所用时间
startTime = DateTime.Now
for(int i = 0i <iterationsi++)
{
t.DoOperation()
}
elasped = DateTime.Now - startTime
Console.WriteLine("Looping Elapsed milliseconds:" + elasped.TotalMilliseconds + "for {0} iterations",iterations)
Console.ReadLine()
}
}
///
/// Reflection 的摘要说明。
///
public class ReflectionTest
{
//保存动态生成并编译的类的type对象
Type theType = null
//保存动态生成类的实例
object theClass = null
///
/// 供Client调用的方法
///
public void DoOperation()
{
//未初始化
if(theType == null)
{
//初始化
GenerateCode()
}
//调用方法时的参数数组(此处为空)
object[] arguments = new object[0]
//调用动态生成类的方法
theType.InvokeMember("SayHello",//要调用的方法名 BindingFlags.Default|BindingFlags.InvokeMethod,//Binding标志,具体参看msdn null,//使用默认Binding对象
theClass,//在theClass实例上调用此方法
arguments//调用方法时的参数数组 )
}
///
/// 运行时生成代码
///
private void GenerateCode()
{
//文件名
string fileName = "Test"
//打开文件,如果不存在,则创建
Stream s = File.Open(fileName + ".cs",FileMode.Create)
//创建一个StreamWriter来写入数据
StreamWriter wrtr = new StreamWriter(s)
//写入动态创建类的源代码
wrtr.WriteLine("// 动态创建Test类")
//类名
string className = "TestClass"
wrtr.WriteLine("using System")
wrtr.WriteLine("class {0}",className)
wrtr.WriteLine("{")
wrtr.WriteLine("/tpublic void SayHello()")
wrtr.WriteLine("/t{")
wrtr.WriteLine("/t/tConsole.WriteLine(/"Hello,World/")")
wrtr.WriteLine("/t}")
wrtr.WriteLine("}")
//关闭StreamWriter和文件
wrtr.Close()
s.Close()
//启动进程编译源文件
//指定参数
ProcessStartInfo psi = new ProcessStartInfo()
//启动cmd.exe
psi.FileName = "cmd.exe"
//cmd.exe的参数,/c-close,完成后关闭后为参数,指定cmd.exe使用csc来编译刚才生成的源文件
string compileString = "/c C://WINNT//Microsoft.NET//Framework//v1.1.4322//csc.exe /optimize+ /target:library {0}.cs"
psi.Arguments = String.Format(compileString,fileName)
//运行时的风格-最小化
psi.WindowStyle = ProcessWindowStyle.Minimized
//启动进程
Process proc = Process.Start(psi)
//指定当前在此进程退出前等待
proc.WaitForExit()
//从编译好的dll文件load一个Assembly
Assembly a = Assembly.LoadFrom(fileName + ".dll")
//创建类的实例
theClass = a.CreateInstance(className)
//取得此类实例的类型
theType = a.GetType(className)
//删除源文件
//File.Delete(flieName + ".cs")
}
}
}
用MFC制作的工程由很多文件构成,它不能象一般C++程序那样随意在类外定义全局变量,在这里要想定义能被工程内多个文件共享的全局变量和函数必须用一些特殊方法才行。实际上有多种方法可以实现,这里只介绍两种方法。一、在应用程序类中定义
用MFC生成的工程中都有一个名为CxxxApp的类,它派生于CWinApp类。这个类主要进行程序的初始化,生成文档、视图对象等工作。我们可以把需要全局访问的变量和函数定义为这个类的成员变量和成员函数,就可以实现全局访问了。
从严格意义上讲,这种变量和函数并不是全局的,因为它仍然只是类中的成员,只是由于我们很容易获得CxxxApp类的指针,所以我们可以在文档、视图、对话框以及各种自定义类中访问到它们,达到与全局变量类似的效果。访问时用函数“AfxGetApp()”获得CxxxApp类的指针,用“AfxGetApp()->成员”访问变量或函数。
例:
Test.h:(应用程序类头文件)
class CTestApp : public CWinApp
{
public:
int x//全局变量
int f(int y)//全局函数
…………
}
Test.cpp:(应用程序类程序文件)
int CTestApp::f(int y) //全局函数定义
{
y++
return y
}
定义在CTestApp类中的变量和函数可以在其它类中被访问。比如在视图的某函数中要访问变量x和函数f():
void CTestView::xyz()
{
CTestApp *app = (CTestApp *)AfxGetApp()//生成指向应用程序类的指针
app->x = 0//访问变量x
int z = app->f(1)//访问函数f()
…………
}
这样,变量x和函数f()可以视作为全局的。
用这种方法实现的全局变量和全局函数虽比较简单,但也有缺点,一是访问不太方便,每次都需要获取应用程序类的指针;再就是把一些与应用程序类本身无关的变量和函数放在里面,使这个类看上去怪怪的,破坏了类的封装。
二、用静态变量和静态函数实现
很喜欢API函数的那种调用方法,不论在哪个类中只要用“::API函数”就可以调用了。合理利用静态类型(static)可以实现与此相似的全局变量和全局函数。
静态变量和静态函数有如下性质:
若在一个类中用关键字static声明数据成员,则这个数据成员就只存在一个拷贝,无论该类创建了多少个实例,它始终只存在一个,即使该类的实例一个也没创建,它也存在。
若在一个类中用关键字static声明函数,该函数可以用“类名::函数名”方式访问,无需引用该类的实例,甚至这个类的实例可以不存在。
利用这个性质实现的全局变量和函数使用起来很方便。
值得注意的是,全局变量和全局函数最好集中封装,不要在文档、视图等类内部定义,这样用起来才有全局的感觉。
例:
1、添加一个没有基类的新类,设类名起为CPublic,姑且称之为公用类
单击“Insert”菜单下的“New Class”命令,选择“Class type”为“Generic Class”,在“Name”栏中填入类名“CPublic”,单击“OK”,则新类建立完毕。
2、包含公用类的头文件,使各个类都能访问它
CPublic的头文件应包含在应用程序类的头文件中,这样在其它类中引用CPublic类时就不需要再包含了。
Test.h:(应用程序类头文件)
#include "Public.h" //包含公用类头文件
class CTestApp : public CWinApp
{
…………
}
3、在公用类中定义全局变量和全局函数,均使用static修饰,静态变量还必须在类外定义和初始化
Public.h:(公用类头文件)
class CPublic
{
public:
CPublic()
virtual ~CPublic()
public:
static int x//全局变量
static int time//全局变量
static int f(int y)//全局函数
…………
}
在公用类中对静态变量进行初始化和定义函数体:
Public.cpp:(公用类程序文件)
int CPublic::x = 0//初始化全局变量
int CPublic::time//定义全局变量
CPublic::CPublic()
{
}
CPublic::~CPublic()
{
}
int CPublic::f(int y) //全局函数,这里不要再加static
{
y++
return y
}
4、全局量的使用
使用变量:CPublic::变量名
使用函数:CPublic::函数()
如在视图的某函数中访问变量x和函数f():
void CTestView::xyz()
{
CPublic::x = 0//访问变量x
CPublic::time = CPublic::f(1)//访问函数f()
…………
}
在其它类中访问x、time和f()的方法与此相同。
5、几点注意:
① 由于静态量可独立于类存在,不需要生成CPublic类的实例。
② 静态数据成员的定义和初始化必须在类外进行,如例中x的初始化;变量time虽然没有初始化,但也必须在类外进行定义。由于没有生成CPublic类的实例,所以它的构造函数和析构函数都不会被执行,在里面做什么工作都没有什么意义。
③ 如果静态函数需要访问CPublic类内的变量,这些变量也必须为静态的。因为非静态量在不生成实例时都不会存在。 如:
class CPublic
{
public:
int x//内部变量
static int f(int y) //全局函数
{
x++
return x
}
…………
}
这里x虽为类内成员,但如果不生成CPublic类的实例,就会出现函数f()存在,而变量x不存在的问题。
总之,用没有实例的类管理全局量是一个不错的选择,它具有集中管理,使用方便的好处。当然,除非特别必要,全局量还是少用为好,一个好的编程者决不会随意滥用全局量的,一个封装做得不好的程序,在修改维护时会让你吃足苦头。
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)