只是一个简单的测试, 用了三种方法来做10万条记录的插入.  不过我没有测试拼10万条sql插入的效率.
应用在:dell inspiron 640M本本上跑的. 1.60双核CPU, 2G内存.  服务器是HP360, 8CPU, 4G内存. SQL2000数据库.
仅供参考.

一.每次都调用ctx的InsertOnSubmit方法把对象放入:
2008-7-18 14:29:55 开始生成100000个对象. 并直接放入ctx; 用时4秒
2008-7-18 14:29:59  开始SubmitChanges;                   用时3分26秒
2008-7-18 14:33:25  完成.

运行时内存占用了4M左右.

二. 先生成一个list, 最后把list调用ctx的InsertAllOnSubmit方法把全部对象放入:
2008-7-18 18:45:06 开始生成100000个对象. 并放入list 用时1秒
2008-7-18 18:45:07 开始把list全部对象加入ctx.  用时2秒
2008-7-18 18:45:09 开始执行submitChange  用时3分33秒. 应该是数据库的原因导致的慢了7秒. 个人认为不重要.
2008-7-18 18:48:42 完成.

运行时内存占用了4M左右.

三.每生成一个记录都调用ctx的insertOnSubmit, 并且都立即执行submitChanges. 每5000个报一次.
2008-7-18 19:41:28
2008-7-18 19:41:29 0
2008-7-18 19:42:08 5000    此5000条用 39 秒
2008-7-18 19:43:39 10000   此5000条用 91 秒 多了52
2008-7-18 19:46:02 15000   此5000条用143 秒 多了52
2008-7-18 19:49:17 20000   此5000条用195 秒 多了52
2008-7-18 19:53:25 25000   此5000条用248 秒 多了53
2008-7-18 19:58:29 30000   此5000条用304 秒 多了56
2008-7-18 20:04:28 35000   此5000条用359 秒 多了55
2008-7-18 20:11:22 40000   此5000条用414 秒 多了55
2008-7-18 20:19:14 45000   此5000条用472 秒 多了58
2008-7-18 20:28:05 50000   此5000条用531 秒 多了59
2008-7-18 20:37:50 55000   此5000条用585 秒 多了54
2008-7-18 20:48:35 60000   此5000条用645 秒 多了60
2008-7-18 21:00:38 65000   此5000条用723 秒 多了78
2008-7-18 21:13:01 70000   此5000条用743 秒 多了20
2008-7-18 21:26:01 75000   此5000条用780 秒 多了37
.... 等不及了, 关了程序了.                
运行时内存占用了4M左右.

越来越慢.

posted @ 2008-07-18 21:54 HAL9000 阅读(1483) | 评论 (27)编辑
     摘要: 多年了,没有什么技术再能让我激动得无法控制住自己,包括WPF的超炫界面功能,我也只是小小地喜悦了一下,但毕竟知道界面设计更多还是美工创意的功夫,见过很多品味不够的开发人员,把自己程序界面搞得花里胡骚,简直得像不小心坐在调色板上的大熊的屁股,只能让人笑话。所以WPF的UI能力似乎离自己还有距离。
  但是,Linq,却真得把我雷到了。在我重新坐下来写这段话之前,我是激动得在屋里转了几圈的,嘴里至少把MS骂了十来句“WC!”,这骂不是怀了恨意的骂,而是怀了敬意的骂,是没办法控制自己兴奋和激动的心情的骂,就像是《朱罗纪公园》里的马尔康姆教授第一眼看到人工DNA造出来的活恐龙时,说的那句话:“这帮狗娘养的真的做了!”
  阅读全文
posted @ 2008-07-17 23:04 HAL9000 阅读(2595) | 评论 (71)编辑

在MSDN上闲逛, 无意中看到一个这样的东西: 屏幕逻辑集成.

 SLI(屏幕逻辑集成,Screen Logic Integration)用于将古老的UNIX绿色终端字符界面的程序包装成为一个web services, 以便在SOA的架构里重用这些古老的业务逻辑. 

比如, 在我们公司中, 业务系统是基于UNIX的终端程序,  一些业务逻辑是在界面上的一些输入框里输入参数, 一些资料, 或是计算结果被显示在屏幕上的一个地方, 这些业务逻辑通过NEON Systems ServiceBuilder可以以web services的方式发布. 其过程如下:

    1.在VS中新建一个NEON Systems ServiceBuilder的项目以建立一个SLI方案.(当然, 前提是你得先安装了这个东西).
    2.向导提供一个录制器, 用来记录你的telnet程序的输入和输出, 记录下屏幕上的所有的输入了信息的地方和输出了信息的地方.
    3.你在向导的录制结果中, 以直观的方式指定哪些是输入参数, 那些区域是输出结果. 还有数据类型等.
    4.向导生成有关的对象模型, 生成webservice.
  
    实际运行时呢? 我猜是这样的:
    1. web services被调用, 参数被传入. webservices程序调用neon的程序.
    2. NEON偷偷以telnet协议连入unix主机, 按录下的按键序列调用unix主机上的程序.
    3. 参数在指定的地方由程序摸拟输入.
    4. 主机程序回应结果, 这些结果本来是要显示在屏幕上的, 现在被NEON得到, 根据指定的位置信息和这些信息对应, 分辩出哪些是什么字段, 返回给web services程序.
    5. web services向调用者回应结果对象.

    这个东西真得有用. :D

MSDN上的文章在这里:
http://www.microsoft.com/china/MSDN/library/KnowledgeBase/kb_0409.aspx

posted @ 2005-11-14 11:30 HAL9000 阅读(727) | 评论 (1)编辑

 

项目组的文档风格问题

 

  叫我怎么说?我们项目组里现在充斥着华而不实的文档作风. 做一件事,这样浮燥,这样不脚踏实地是不行的.

 

  写工作文档,规范严格是重要的,但并不是要把简单问题往复杂了搞,不是要把实际问题抽象化,不是要去找一些意义含糊的词语来表达,不是要把一句话可以说明白的意思用一大段话来说得人人都看不懂!

 

  说到工作文档,我想有下面几点要做好,就够了.

  一.句法不能出问题:

  • 主谓宾一个也不能少.
  • 如果主谓宾的词语不能确切地,无岐义地表达事实,那么必须用确切的定语\状语\补语成分.
  • 不推荐应用定状补定子句.如果需要的定状补成分是一个子句,那么尽可能分句,在另一句中对于需要限制定的语素进行详细说明.
  • 标点符号不能出错,括号内外的标点要遵守括号标点的惯例.

 

  二.用词:

  用词的原则为:

  • 能简单不复杂.
  • 能用常用字词表达,则不用冷僻词.
  • 能用有确切含义的技术名词,则不用俗称或是其他非技术名词.
  • 能具体不抽象.例如要传达"椅子"的概念,就用"椅子"这个词,而不是采用"泛化单式坐恣人体支撑家俱"这样的词,虽然然这样说起来显得很高档.
  • 英文缩写词提供术语解释.
  • 有数值指标的,则不用比较级形容词,如"数据库的容量要达到非常大的容量,在大容量下的性能要在可容忍的限度内."这样的话实际上没有传达信息.而"数据库设计要支持1亿条记录的容量,同在达到1亿条数据时,用身份证号查询记录时,得到结果的时间最长不能大于0.1秒"这样的话就精确定义了信息.

看来我们项目组里有些人需要的不是专业技能, 而是需要补习语文!

 

posted @ 2005-09-16 11:49 HAL9000 阅读(624) | 评论 (14)编辑

求助: VC++ 中 DLL编译时结构体成员对齐的问题

现在我们有一个需求, 要求我们用VC++编写一个DLL, 叫GT2MQ.dll, 输出一些函数供一种叫GRAPHTALK(GT)的语言使用, 在这些函数的实现里调用了另一个其他厂商提供的中件间产品的DLL函数(adapter.dll).

GT对DLL函数的调用是有要求的, 其中最重要的是必须在编译时指定结构成员按1字节对齐, 否则GT在调用这个DLL的函数时会出现非法操作.

在GT2MQ里的方法调用adapter.dll的一个方法时, 需要传入一个结构体的指针做为参数, 这个结构体的定定义如下:
/*消息结构*/
typedef struct BusMessage
{
 char messageId[50];
 char correlId[50];
 char appMessageId[30];
 char version[30];
 char bodyType[20];
 char bodyCategory[20];
 char timeStampCreated[30];
 char timeStampExpired[30];
 char srcLogicalId[30];
 char dstLogicalId[30];
 char authenticationId[30];
 char commandMode[30];
 char txnScope[30];
 char *standardBody;
 char *body;
 char priority[20];
 char persistence[10];
 char expiry[10];
 char traceLevel[10];
 char publish[10];
 char backup[10];
 char messageName[384];
 char encoding[30];
 char msgCharset[30];

 long msglen;/*发送消息的长度*/
 long rcvlen;/*接收消息需要的内存*/
 
}BusMessage, *ptrBusMessage;

当我们的DLL函数新建了这个结构体, 清零, 并填写了必要的字段后, 把结构的指针做为参数调用adapter.dll中的一个函数, 然而这时后发现无论如何, 这个方法调用都不成功. 返回的错误是说msglen的字段没有填值. 但那个字段明明是填入了值的.

由于adapter.dll没有源码, 只好通过汇编代码来debug, 才发现这个结构体在我们的dll里和在adapter.dll里对字段寻址时地址不一样, 我们的DLL对msglen的寻址是msg+932, 而adapter.dll对同一个字段的寻址是msg+936!

通过手工计算, 确定msglen成员的偏移值应取932, 但是如是果同一个结构体定义放在一个新建的win32工程中时, 查看汇编代码, 就发现是按936寻址的.

后来再进一步查找, 发现问题出在下面两个字段的定址上:standardBody和msglen, 这两个字段在定址时都向后移动了两个字节, 造成了一共四个字节的偏移, 这使得成员访问数据时出错.

我们怀疑是由于我们的GT2MQ.dll项目里的那个结构成员对齐选项设为"1字节对齐"(/Zp1)造成的, 但是无论我们把这个参数设为多少, 都不会消除这个问题:我们的DLL始终不会为那两个字段增加两个字节的偏移. 何况我们项目的要求是GT2MQ.dll必须指定/Zp1选项, 即使这样解决了也无法满足要求.

我们目前的解决办法是: 在结构体里在standardBody和msglen之前各增加了一个字段: char Reserved1[2]和char Reserved2[2]来强迫我们的DLL为之后的成员定址时加一. 但是感觉这样做并不是很妥当, 必竟我们修改了厂商提供的头文件, 而同一头文件在其他项目里是不会出现问题的.

诚求更好的解决方案, 或是知道如何调整项目设置的高手请赐教!

posted @ 2005-09-05 10:02 HAL9000 阅读(1249) | 评论 (5)编辑
一定得选最时摩的外国系统.
雇法国公司?
搞就搞最 high level 的方法论.
IAA模型直接用上.
SOW最少也得整上三四百页.
什么再保呀,精算呀,两核呀, 银保呀.
能整的全给他划进scope里去.
这边搞个技术组, 那边来个业务组.
办公室门口站一白人经理.
打领带, 笑容特虚伪的那种.
打工的一进门, 甭管是写程序的还是搞需求的都得跟经理打招呼:
morning, 我的output昨天已经加班derived了.
打心里头没底的腔儿.
倍儿没面子.
项目组里再设个资深专家团.
方法论用RUP的.
一天光workshop就是十多个小时.
再请一个美国IBM的顾问,
每天就来工作一个小时.
就是一个字儿----贵.
光确定一个项目组人员结构就要好几十万的.
周围其他项目组不是迭代式实施就是敏捷式开发.
你要是一张口只会讲OOAD呀.
你都不好意思和人家打招呼!
你说这样的项目, 得多少时间上线?
我觉得怎么着也得大后年吧!
大后年? 那只够完成需求分析的.
DAY1定在奥运会后!
你别嫌慢, 这已经是简化的process了.
你得研究甲方的心理.
肯出几个亿做project的,
在乎的就是过程.
这什么叫样板工程? 你知道吗?
样板工程就是不管搞什么project,
都用最考究的方法, 不用最直接的方法.
所以, 我们做IT项目的口号就是
不求能出活, 但求最规范.
posted @ 2005-08-31 15:07 HAL9000 阅读(535) | 评论 (1)编辑
     摘要: 1.1. Windows界面设计标准1.1.1. 易用性l 界面元素的名称、标签应该易懂,用词准确,避免使用模楞两可的字眼,要与同一界面上的其他元素易于区分,能望文知意最好。理想的情况是用户不用查阅帮助就能知道该界面的功能并进行相关的正确操作作。 l disable而不是not visible。l 完成相同或相近功能的按钮用GoupBox框起来,常用按钮要支持快捷方式。 l 完成同一功能或任务的元... 阅读全文
posted @ 2005-07-28 14:25 HAL9000 阅读(1851) | 评论 (2)编辑

经过无数次的重装, 删除, 终于明白了, 必须要先装informix cli 2.82(这是唯一一个可以和oracle 9.2i共存的informix cli 32 版本), 再装oracle 9.2i cli, 才可以同时访问两种数据库的odbc 或oledb的连接, 不然的话就会在新建oracle92的 ODBC或是OLEDB连接时出现找不到oracle驱动程序的问题.

切记切记!

posted @ 2005-06-21 19:37 HAL9000 阅读(705) | 评论 (0)编辑

同一个输出流, 不可以在多线程上共用. 如果要共用, 一定要使用临界段.
不同的输出流, 在多线程上并发处理时互相没有影响.
代码说话:

public static void testmulttts()
{
    Thread [] arT 
= new Thread[8];
    
for (int i = 0; i < arT.Length; i ++)
    {
        arT[i] 
= new Thread(new ThreadStart(testtts));
    }

    
foreach(Thread t in arT)
    {
        t.Start();
        Thread.Sleep(
500);
        System.Console.WriteLine(
"线程已经启动!");
    }            
}


public static void testtts()
{

    
///http://msdn.microsoft.com/library/default.asp?url=/library/en-us/SAPI51sr/html/ispvoice_speak.asp
    SpeechLib.SpVoiceClass sp = new SpeechLib.SpVoiceClass();            

    SpeechLib.SpFileStreamClass fs 
= new SpeechLib.SpFileStreamClass();            
    fs.Format.Type 
= SpeechLib.SpeechAudioFormatType.SAFT8kHz8BitMono;
    fs.Open(
"c:\\" + Guid.NewGuid().ToString() + ".wav" , SpeechLib.SpeechStreamFileMode.SSFMCreateForWrite, false);
    
// sp.AudioOutputStream = fs;
    
// The format of selection criteria is 
    
//"Attribute = Value" and "Attribute != Value." 
    
// Voice attributes include 
    
//"Gender," "Age," "Name," "Language," and "Vendor."
    
// 上述这些属性的值可以从注册表的
    
//HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech\Voices\Tokens\MSSimplifiedChineseVoice\Attributes
    
// 看到
    SpeechLib.ISpeechObjectTokens sps = sp.GetVoices("Language = 409""");
    
for (int i = 0; i < sps.Count; i ++)
    {
        sp.Voice 
= sps.Item(i);

        
lock(typeof(Class1))
        {
            sp.Speak(
"speak in English."
                SpeechLib.SpeechVoiceSpeakFlags.SVSFDefault);
        }
    }
    sps 
= sp.GetVoices("Language = 804""");
    
if (sps.Count > 0)
    {
        sp.Voice 
= sps.Item(0);
        
lock(typeof(Class1))
        {
            sp.Speak(
"中华人民共和国, 中央人民政府, 成立了!"
                SpeechLib.SpeechVoiceSpeakFlags.SVSFDefault);
        }
    }
    fs.Close();
    Marshal.ReleaseComObject(sp);
    Console.WriteLine(
"线程录音完成.");
}
}
posted @ 2005-06-05 15:40 HAL9000 阅读(904) | 评论 (1)编辑

先决条件:

装了office2000或更新版本中带的MS语音输入法. 这可能就是MS中国研究院的成果之一. 有语音输入功能和语音拼读功能.

下载ms speech api sdk 5.0或5.1, 如果只用C#开发, 则不用装这个, 如果希望用C++开发, 加装语音库之类的, 不妨也装这个好了. 装了这个, 第一条的也就包含了.

C#工程里加上对com对象"Microsoft Speech API 5.0"的引用. Interop而已.

不再多说, 只贴个代码, 以备日后参考:

public static void testtts()
{
    
//参考文档的起始链接在:
    
//http://msdn.microsoft.com/library/default.asp?url=/library/en-us/SAPI51sr/html/ispvoice_speak.asp

    
// 引擎COM对象.
    SpeechLib.SpVoiceClass sp = new SpeechLib.SpVoiceClass();            
    
    
// 朗读的内容到一个文件流里去.
    SpeechLib.SpFileStreamClass fs = new SpeechLib.SpFileStreamClass();
    
//设定流的格式, 48kHZ, 16Bit, 立体声. 如果是电话音质, 8K8bit单声道就可以了.
    fs.Format.Type = SpeechLib.SpeechAudioFormatType.SAFT48kHz16BitStereo;
    fs.Open(
"c:\\test.wav", SpeechLib.SpeechStreamFileMode.SSFMCreateForWrite, false);
    sp.AudioOutputStream 
= fs;    // 如果不指定这个内容, 那就会在计算机的声卡上放出来.
    
// The format of selection criteria is 
    
//"Attribute = Value" and "Attribute != Value." 
    
// Voice attributes include 
    
//"Gender," "Age," "Name," "Language," and "Vendor."
    
// 上述这些属性的值可以从注册表的
    
//HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech\Voices\Tokens\MSSimplifiedChineseVoice\Attributes
    
// 看到

    
// 得到属性符合指定要求的所有的拼读token. "Language = 409"表示得到所有的英文拼读器. 等号两边的空格不可少! 
    // 如果有多个过滤条件要指定, 中间用分号分开, 如要指定英文女声, 则为
    // "Language = 409; Gender = Female"
    SpeechLib.ISpeechObjectTokens sps = sp.GetVoices("Language = 409""");
    
// 可能有多个拼读器. 咱们每个都用一遍,  是不同的嗓音, 有男有女.
    for (int i = 0; i < sps.Count; i ++)
    {
        sp.Voice 
= sps.Item(i);    //这里这个圆括号不是我写错了, 就是这样的.这是一个方法,不是索引器.

        sp.Speak(
"User experience and interface design in the context of creating software represents an approach that puts the user, rather than the system, at the center of the process."
            SpeechLib.SpeechVoiceSpeakFlags.SVSFDefault);
        
// 可以用标志位指定异步调用这个方法. 
    }

    
// 得到中文拼读器, 因为目前只有一个, 也就不用for了.
    sps = sp.GetVoices("Language = 804""");
    
if (sps.Count > 0)
    {
        sp.Voice 
= sps.Item(0);
        sp.Speak(
"中华人民共和国, 中央人民政府, 成立了!."
            SpeechLib.SpeechVoiceSpeakFlags.SVSFDefault);
    }
    fs.Close();
    Marshal.ReleaseComObject(sp);
}


posted @ 2005-06-04 22:56 HAL9000 阅读(2416) | 评论 (7)编辑
问题一: 自已写到一个类, 其中有一个属性是字串型, 是用来保存一个文件名的,  这个类需要客户在使用时能在PropertyGrid里runtime修改内容, 友好的方式当然是让客户在PropertyGrid里可以有一个"..."的按钮, 点一下之后打开一个openfiledialog, 选择一个文件之后返回, 文件的全路径就放在属性值的框里了. 如何达到这个目的?

比如这个类如下:
public class class1
{
    
public class1()
    
{    
    }

    
    
// 

    
private string _s;
    
public string s
    
{
        
get{return this._s;}
        
set{this._s = value;}
    }

}


这样的话在PropertyGrid里s属性的后面只有一个简简单单的编辑框, 为了使s的编辑区可以出现一个"..." 按钮, 并且可以用文件打开对话框选择文件, 可以使用EditorAttribute属性对这个属性进行标记:

[Editor(
typeof(System.Windows.Forms.Design.FileNameEditor), 
        
typeof(System.Drawing.Design.UITypeEditor))]
public string S
{
    
get{return this._s;}
    
set{this._s = value;}
}

FileNameEditor类提供了一个打开文件的对话框, 以编辑属性值, 这个类派生于UITypeEditor类, UITypeEditor是所有设计时界面的基类.

这样就可以达到有文件对话框的目的了, 但是如果想要指定只选择某一种文件类型, 如"WAV"文件, 那就得派生FileNameEditor, 重写有关的方法.

public class SoundFileEditor:System.Windows.Forms.Design.FileNameEditor
{
    
protected override void InitializeDialog(OpenFileDialog openFileDialog)
    {
        
base.InitializeDialog (openFileDialog);
        
// 在基类初始代完对话框之后, 可以对这个对话框做一些手脚.
        openFileDialog.Filter = "wav and vox file(*.wav, *.vox)|*.wav;*.vox|wav files (*.wav)|*.wav|vox files (*.vox)|*.vox|All files (*.*)|*.*";
    }
}

再把Class1中的S的EditorAttribute改为派生的这个子类, 现在对话框里的文件过滤器改为你想要的了.

你甚至可以从UITypeEditor自己重新派生一个子类出来, 自己写一个能弹出"保存文件"对话框的UI编辑类. 注意在重写UITypeEditor的
public virtual new System.Object EditValue ( System.ComponentModel.ITypeDescriptorContext context , System.IServiceProvider provider , System.Object value )
方法, 注意返回自己需要对象就可以了.

问题二:  如何设定一个类的"默认值编辑器"?
例如: 比如有一个类叫SoundFileName专门用来处理声音文件名, 如果Class1中有一个属性FileName是SoundFileName类型, 这个属性在PropertyGrid里编辑器里默认情况下是没有办法编辑的, 为了让SoundFileName类可以在propertyGrid里可以编辑, 必须对SoundFileName进行属性标志, 指定一个默认的编辑器. 假定我们还是希望通过"打开文件"对话框来指定一个文件的方式生成一个SoundFileName对象, 那么我们可以写一个从UITypeEditor中直接或间接派生的子类, 以完成编辑对象内容的操作.

如下代码所示, 这个专门编辑SoundFileName对象的类叫SoundfileNameEditor, 我们随后实现它, 现在先看SoundFileName的实现. 注意class之前的标记:

[EditorAttribute(typeof(SoundFileNameEitor), 
        
typeof (System.Drawing.Design.UITypeEditor))] 
public class SoundFileName
{
    
private string _filename;    
    
public string FileName
    {
        
get{return _filename;}
    }

    
public SoundFileName(string s)
    {
        
this._filename = s;
    }
}

这里定义了此类的值编辑器为SoundFileNameEditor类, 这个类我们需要从UITypeEditor或是其子类中派生出来, 重写其EditValue方法, 以可以返回一个SoundFileName对象.

为了省事, 我就不再从UITypeEditor派生了, 而是从SoundFileEditor派生, SoundFileEditor已经把文件名过滤器修改了, 但是SoundFileEditor的EditValue返回的是一个字串, 这次只要修改SoundFileEditor的EditValue的值就可以了.

public class SoundFileNameEditor: SoundFileEditor
{
    
public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
    {
        SoundFileName sfn 
= value as SoundFileName;
        
        
return new SoundFileName(base.EditValue (context, provider, sfn==null?"":sfn.FileName) as string);
    }
}

注意, 这个EditValue总是会返回一个新的对象, 把从前的对象扔掉, 你可以通过判断value是不是null来决定是否新建一个对象, 还是只是修正一下其中的文件名, 这里不再多说了.

现在你在PropertyGrid里可以编辑SoundFileNmae对象了, 编辑器弹出一个打开文件对话框, 选择了文件之后, 根据文件名建立了一个SoundFileName对象.

最后提示一下, 不知道你注意到了没有, 当选择了文件名建立了一个SoundFileName对象之后, 在编辑框里的内容是"testanything.SoundFileName", 用户看起来不会太高兴, 也不直观, 这个也好办, 你可以重写SoundFileName的ToString()方法来用任何方式显示你想要内容.
posted @ 2005-06-02 17:17 HAL9000 阅读(1649) | 评论 (3)编辑

process早就有办法了, 只不过我没有注意.

如调用一个命令行:"cmd /c dir c:\winnt"; 把结果放到一个字符串里.

ProcessStartInfo psi = new ProcessStartInfo("cmd"" /c dir c:\winnt");
psi.RedirectStandardOutput 
= true;
psi.UseShellExecute 
= false;
Process p 
= Process.Start(psi);

output 
= p.StandardOutput.ReadToEnd();
p.WaitForExit();
注意那个waitforexit()一定要放到readtoend之后. MSDN里这样说:


    process组件通过管道与子进程通信。如果子进程写入管道的数据多得足以填满缓冲区,则子进程将一直会阻塞到父进程从管道读取数据时为止。如果应用程序将所有输出读取到标准错误和标准输出,则这会导致死锁。

    意思就是: 如果waitforexit在前, 那么如果数据太多而超出缓冲期大小, 子程序就会等着消费者把数据读出来, 可是这时候由于waitforexit正在阻塞, 做为消费者的过程序readtoend无法执行, 因而导致了死锁.

   除了上面的, 还可以用程序交互:

ProcessStartInfo psi = new ProcessStartInfo("cmd");
psi.RedirectStandardOutput 
= true;
psi.RedirectStandardInput 
= true;
psi.UseShellExecute 
= false;
Process p 
= Process.Start(psi);

p.StandardInput.WriteLine(
@"dir c:\winnt");
p.StandardInput.WriteLine(
@"ver");
p.StandardInput.WriteLine(
@"exit");

output 
= p.StandardOutput.ReadToEnd();
p.WaitForExit();

    重定义了stdin, 执行cmd程序, 进入了命令行交互, 然后向标准输入里写若干个命令, 回车, 有意思, 执行了! 最后千万别忘记了用"exit"命令中断cmd的执行, 不然后面的readtoend时, 永远也不会读到END, 程序又阻塞在这里不会退出. 


    最后, MSDN提到了standarderror, 如果同时重定向了stdout和stderr, 那么不当的方式也会出现死锁: 如:
string output = p.StandardOutput.ReadToEnd();
string error = p.StandardError.ReadToEnd();
p.WaitForExit();

    MSDN说程序先读了stdout, 完了之后再读stderr, 如果子进程在执行时向stderr写了内容, 那么就会死锁. 我想了一会儿, 没想明白. 如果程序在两个流里都写入了, 那么第一个读stdout的动作完成之前, stderror的内容留着不就行了? 但是没有时间试了.
    MSDN建议用两个线程来处理不同重定向流.  这是个好办法.
posted @ 2005-05-12 16:43 HAL9000 阅读(2433) | 评论 (2)编辑
    寄来了门票, "2005年中国IT发展动向", 上印票价500. 是么! 看来是要去听了, 500元, 好值钱呀! 不要钱就送来了?
   
    地址在北京饭店, 去时已经是10:30, 交了票, 一问, 什么都没有, 资料也发完了, 午饭票也发完了, 进场看看, 座位也坐完了. 还有人在离开, 有人在进来, 有人在出去. 来来往往, 后面还有人在卖书, 1元一本的PC世界, 有人在买, 有人在卖音箱, 有人在卖USB台灯, 哦, 不是卖的, 是在送, 只要订一年的杂志就送一个. 还有人在卖煎饼果子...哦不是, 我早上没吃饭, 饿得有点幻觉.

    下面的人在赶集, 上面有个人正在有一句没一句地讲, 讲什么呢? 从前有座山... 不对不对, 他在讲"整合驱动创新", 我还真是不知道这是什么意思. 似乎都是很流行的词, 我觉得自己回到了从前学英语时的那种场景, 每个词都认得, 就是不知道放到一起是什么意思. 我索性到第一排去听, 第一排都有水喝, 后面的就没有了. 我站在一边上听, 那人说是什么大中华地区总裁什么的. 正在讲一些PPT上的内容. PPT上的内容我也看不懂, 上一句和下一句也没有什么联系, 大纲和小标题之间也看来出有什么联系. 没有联系得我现在一句话也想不起来.

    然后就听他讲, 他突然抱怨"这个屏幕可能有什么问题", 他的幻灯片里的曲线是该向上的, 那该死的屏幕把它显示错了, 显示成向右的水平线了. 我开始考虑是不是显示驱动有一些问题, 在DX状态下PPT播放时会不会造成一些不兼容, 那个视频线会不会中途CUAN改他PPT的内容, 都排除了之后我才意识到这个说法很高雅, 我一定得学会这一招, 在合适的时候认为自己的屏幕把内容给显示错了.

    之后的内容我还是不大明白, 他又说了一些零库存的事儿, 后来他终于说到SRA, 面向服务架构企业应用什么的, 我开始有点精神了, 总算知道说到哪儿了. 他说互联网就是最大的异构化的服务体系, 要把这些异构的同构起来. 我更有精神了. 我想听听他有什么好办法把这玩意儿同构起来.

    可是他又不说如何同构, 只说整合驱动创新. 原来这三个词连到一起的意思是"整合了, 就会驱动IT人员去驱新", 然后又峰回路转, 说选用什么中间件很重要. 我正在想这么不知云的会议靠什么钱来支持, 听到这个话就有点明白了, 翻了翻日程表, 这个讲者是IBM的大中华总经理什么的, 然后就听他说他们IBM的中间件很好.

    我正等着他讲IBM的中间件, 他的PPT突然说谢谢大家. 我以为他会再骂一次他的屏幕乱改他的内容, 可是他下来了. 主持人上去报幕说下一讲是谈EPSON的"微墨滴技术构建企业打印平台". 我看看下午的议程, 有"构建64位计算平台", "高性能计算的平民化趋势", "网络架构下企业应用中的UPS不间断电源保证"什么的. 还有观众抽奖, 第二次抽奖....

    这时一个日本人上去, 说"我给你起哇". 然后开始哇拉哇拉讲.

    我饿极了, 就走了.
posted @ 2005-04-27 17:18 HAL9000 阅读(1143) | 评论 (6)编辑
花了155元.
 早有这个打算, 一直要考试, 学习等, 不敢买, 上周终于考试完了, 立即下手买回来.
昨天看到凌晨一点. 放不下了.

考试真烦, 明明答得不错, 可是还要担心不及格, 只因为老师想让不及格就可以给个50多分. 上次也答得不错, 可是具然还是50多分, 知情者说是老师嫌我们没有孝敬他, 故意把及格的都拉下来了. 50多分的就是已经及格的. 这社会, 满是邪恶.
posted @ 2005-04-19 15:42 HAL9000 阅读(592) | 评论 (0)编辑

这个卡和dialogic看来还是有一些差距的, 只支持8k8bit的声音文间, 其他的总是会出现一些奇怪的事情.

posted @ 2005-04-19 15:37 HAL9000 阅读(538) | 评论 (0)编辑

如何调用方法?

本示例阐释如何通过反射调用各种方法。由于所调用方法的名称存储在字符串中,因此该机制提供在运行时(而不是在设计时)指定要调用的方法的功能,提供了使您的用户可以控制调用哪个特定方法的余地。尽管本演示集中于调用方法,如果需要您还可以设置和获取属性和字段。有关本主题的另一个实例示教,请参阅如何使用数学函数主题下的示例。

 
C# ListMembers.aspx

[运行示例] | [查看源代码]

在许多代码方案中,在执行任务以前您知道要实现的任务。因此,您可以指定需要调用的方法以及需要传递给它们的参数。但是,还有一些情况下您可能希望根据特定方案或用户操作动态调用方法。该功能可通过 Reflection 命名空间使用,方法是使用 Type 对象上的 InvokeMember 方法。

您还可以进行其他操作,如获取或设置指定属性的值。这些操作可通过 BindingFlags 枚举使用。InvokeMethod 的第二个参数是您指定的 BindingFlags 操作的组合。例如,如果想调用某个类上的静态方法,可以在 BindingFlagsInvokeMethod BindingFlag 中包括该静态元素。下面的示例展示如何调用名为 SayHello 的假想方法,其中 SayHello 是静态方法。

// calling a static method, receiving no arguments

// don't forget that we are using object in the reflection namespace...
using System;
using System.Reflection;

public class Invoke {

	public static void Main (String [] cmdargs) {

		// Declare a type object, used to call our InvokeMember method...
		Type t = typeof (TestClass);

		// BindingFlags has three bitor'ed elements. Default indicates
		// that default binding rules should be applied.
		t.InvokeMember ("SayHello",
				BindingFlags.Default | BindingFlags.InvokeMethod
				| BindingFlags.Static, null,
				null, new object [] {});
	}
}
C# VB  

快速查看一下传递给 Invoke 方法的其余参数。传递的第一个空参数请求使用默认联编程序绑定正在调用的方法。当调用默认联编程序时,请包含默认的 BindingFlags。第三个参数可以不为空,您可以指定一个 Binder 对象,它定义一组属性并启用绑定,这可能涉及选择重载方法或强制参数类型。第二个空参数是您在其上调用所选方法的对象。最后,传递由成员接收的参数对象数组。在本例中,SayHello 方法不接收任何参数,因此传递一个空数组。

下面的情况略有不同。调用名为 ComputeSum 的另一个静态方法,但是在此情况下,此方法需要两个参数。因此,用这些参数填充一个对象数组,并将它们作为最后一个参数传递到 InvokeMember 中。

// Calling a static method, which needs arguments
object [] args = new object [] {100.09, 184.45};


// we know that this particular method returns a value, being the computed sum,
// so we create a variable to hold the return
// note the datatype of the return is object, the only datatype InvokeMethod returns...
object result;

// invoke the method. Note the change in the last parameter: the array we populated...
result = t.InvokeMember ("ComputeSum", BindingFlags.Default | _
		BindingFlags.InvokeMethod | BindingFlags.Static,
		null, null, args);

// write the results to the user's console...
Console.WriteLine ("{0} + {1} = {2}", args[0], args[1], result);
C# VB  

在前两个示例中,已调用了静态方法。还可以调用实例方法。若要这样做,将您要在其上调用方法的类型的对象作为第三个参数传递。本示例还展示为了使用 InvokeMember,您不必有实际的 Type 对象。在此情况下,通常将希望使用所拥有的类实例来调用 GetType,如下面的示例所示。注意由于未调用静态方法,所以 BindingFlags 已更改。

// Calling  an instance method
// we need an object reference to invoke an instance member
TestClass c = new TestClass ();


// use the instance of our class to call GetType
// we no longer include the Static element in BindingFlags for our |
// the fourth parameter is no longer null: we instead pass an instance
// of the object we wish to invoke our method on
c.GetType().InvokeMember ("AddUp", BindingFlags.Default | BindingFlags.InvokeMethod,
			null, c, new object [] {});
c.GetType().InvokeMember ("AddUp", BindingFlags.Default | BindingFlags.InvokeMethod,
			null, c, new object [] {});
C# VB  

有时不想调用方法,而需要调用其他成员,如属性或字段。若要实现它,只需更改 BindingFlags 组合(而不是 InvokeMethod)以包含适当元素即可。下面的示例展示获取和设置字段值。所讨论字段不是静态字段,因此需要创建一个对象实例来请求该字段。设置字段值时,需要将所设置的值作为对象数组参数的唯一元素传递。获取值时,需要将 InvokeMember 方法的返回类型分配给一个对象。

// Setting a field. Assume we are using the same Type and Class declared in the
// previous examples (t and c). The field we are setting is the Name field
// note the BindingFlags argument now includes SetField rather thanInvokeMember
// Further, this is an instance field, so we pass the instance of our class
t.InvokeMember ("Name", BindingFlags.Default | BindingFlags.SetField,
		null, c, new object [] {"NewName"});

// similar usage...
result = t.InvokeMember ("Name", BindingFlags.Default | BindingFlags.GetField,
		null, c, new object [] {});

Console.WriteLine ("Name == {0}", result);
C# VB  

还可以获取和设置属性,但在本示例中,假定所设置属性是一个具有多个元素的数组或集合。若要指定特定元素的设置,您需要指定索引。若要设置属性,请分配 BindingFlags.SetProperty。若要指定属性的集合索引或数组索引,请将要设置元素的索引值放在对象数组的第一个元素中,然后将要设置的值作为第二个元素。若要取回该属性,请将索引作为对象数组中的唯一元素传递,指定 BindingFlags.GetProperty。

// Set an indexed property value
int index = 3;

// specify BindingFlags.SetProperty, and because this is an instance property,
// pass the object to call the property on (c). In the object array, make two elements,
// the first being the index, and the second being the value to set
t.InvokeMember ("Item", BindingFlags.Default |BindingFlags.SetProperty,
			null, c, new object [] {index, "NewValue"});

// Get an indexed property value
// specify BindingFlags.GetProperty, and because this is an instance property,
// pass the object to call the property on (c). In the object array, specify the index only
result = t.InvokeMember ("Item", BindingFlags.Default |BindingFlags.GetProperty,
			null, c, new object [] {index});

Console.WriteLine ("Item[{0}] == {1}", index, result);
C# VB  

还可以使用命名参数,在此情况下需要使用 InvokeMember 方法的另一个重载版本。像迄今一直进行的那样创建对象参数的数组,并创建所传递参数的名称的字符串数组。您要使用的重载方法接受参数名列表作为最后一个参数,并接受要设置的值的列表作为第五个参数。在本演示中,所有其他参数都可以为空(当然前两个除外)。

// Calling a method using named arguments

// the argument array, and the parameter name array. Obviously, you will need
// to determine the names of the parameters in advance
object[] argValues = new object [] {"Mouse", "Micky"};
String [] argNames = new String [] {"lastName", "firstName"};

// the first five parameters for this overloaded method are the same as the
// the five parameters we have used to this point. The final parameter needs to be
// set to the names of the parameters
t.InvokeMember ("PrintName", BindingFlags.Default | BindingFlags.InvokeMethod,
			null, null, argValues, null, null, argNames);
C# VB  

下一个示例展示如何调用类上的默认成员。确保在其上进行调用的类指定有默认成员。然后在 InvokeMember 方法中,不要指定要调用成员的名称,如本示例所示。

// our class with it's default member specified, using the defaultmemeber attribute
[DefaultMemberAttribute ("PrintTime")]
public class TestClass2 {

	public void PrintTime () {
		Console.WriteLine (DateTime.Now);
	}
}

// the client code that uses the above class...


Type t3 = typeof (TestClass2);
t3.InvokeMember ("", BindingFlags.Default |BindingFlags.InvokeMethod,
			null, new TestClass2(), new object [] {});
C# VB  

最后一个示例使用略有不同的过程调用方法。不直接使用 Type 对象,而是直接创建一个单独的 MethodInfo 对象来表示将调用的方法。然后调用 MethodInfo 对象上的 Invoke 方法,传递需要在其上调用方法的对象的实例(在要调用实例方法的情况下,但是,如果方法是静态的,则为空)。像以前一样,需要参数的对象数组。如果需要,该特定示例允许您通过引用传递参数。

// Invoking a ByRef member
MethodInfo m = t.GetMethod("Swap");


args = new object[2];
args[0] = 1;
args[1] = 2;

m.Invoke(new TestClass(),args);

Console.WriteLine ("{0}, {1}", args[0], args[1]);
C# VB  

posted @ 2005-03-11 17:32 HAL9000 阅读(1679) | 评论 (0)编辑

如何列出某类型的所有成员

本示例使您可以列出给定数据类型的成员。列出类型成员的功能是快速发现哪些元素可用的很好方式。它是在系统中进行报告以及帮助开发用户文档的重要工具。使用 Reflection 命名空间,您可以控制希望显示给用户的成员类型以及其他信息(如特定方法的可见性)。还可以获取类中所有成员的信息,或仅指定某些子集(如方法或字段)。

 
C# ListMembers.aspx

[运行示例] | [查看源代码]

您可能想知道为何获取特定类型的信息很重要。毕竟,这就是帮助系统和帮助文档的用途,不是吗?下面的示例可以帮助您创建用户文档,或用于帮助动态调用方法或设置属性。

需要执行以下几个步骤。首先,需要获取用户希望使用的类型(以字符串的形式)。确定了要使用的类型后,需要分配一个对象来表示该类型。这将进行两项工作:创建后面步骤可以使用的对象,还确保指定类型存在并且可被系统找到。下面的示例向 System.String 类型分配一个对象。注意,尽管此处示例中通过“控制台”(Console) 对象向用户提供反馈,实际示例却将反馈发送给一个 ASP.NET 标签对象。但解释相同。

// don't forget your using statements at the top of your code...
Using System;
Using System.Reflection;

// class declaration, and method declaration...

// remember that this string is case-sensitive, so be careful
Type t = Type.GetType("System.String");

// check to see if we have a valid value. If our object is null, the type does not exist...
if (t == null) {
	// Don't assume that it is a SYSTEM datatype...
	Console.WriteLine("Please ensure you specify only valid types in the type field.");
	Console.WriteLine("REMEMBER: The Case matters (Byte is not the same as byte).");

	return; // don't continue processing
}
C# VB  

有了有效的类型对象以后,下一个问题是希望为类型检索什么类型的成员?是需要方法、静态方法还是实例字段?在 Reflection 命名空间中,有一组 Info 对象,每个对象表示您系统的一组不同成员。例如,有一个 MethodInfo 对象可表示有关某方法的信息。还有一个一般 MemberInfo 对象,它表示给定类中可以存在的所有成员。

使用该信息,您可设置以下数组来查看刚刚创建的类型,并弄清类型中有哪种类型的信息。下面示例中的“位”运算符(|符号,或 Visual Basic 中的 BitOr)请求满足指定约束的类型的所有信息。该示例展示如何获取所有字段和所有方法。

// declare and populate the arrays to hold the information...
FieldInfo [] fi = t.GetFields (BindingFlags.Static |
		BindingFlags.NonPublic | BindingFlags.Public);     // fields

MethodInfo [] mi = t.GetMethods (BindingFlags.Static |
		BindingFlags.NonPublic | BindingFlags.Public);     // methods
C# VB  

下一步是迭代通过每个数组,并在屏幕上列出数组中的元素(显然,您将实际处理这些元素或标识数组中的某个特定元素)。有多种方法可以进行该操作,但在该示例中使用 Foreach(Visual Basic 中为 For Each)语句。



// iterate through all the method members
foreach (MethodInfo m in mi) {
	Console.WriteLine(m);
}

// iterate through all the field members
foreach (FieldInfo f in fi) {
	Console.WriteLine(f);
}

// etc.... for each array type
C# VB  

前面的代码工作良好,但请注意两条 Foreach(Visual Basic 中为 For Each)语句多么类似。将所有这些都写出来非常费力而且杂乱(并且如果以后更改代码,可能需要大量维护)。可以通过返回到 MemberInfo 对象来规避这一点。MemberInfo 对象包括所有可能的信息集(方法、字段和接口等等)。这可以对我们有所帮助,因为我们可以将以前的多个 Foreach 语句写成一个语句,传入数组以进行分析。

// call the routine below, passing the relevant array we made in the previous step
PrintMembers( mi ); // the method information
PrintMembers( fi ); // the field information

void PrintMembers (MemberInfo [] ms ) {



	// MemberInfo is the generic info object. This can be any of the other info objects.
	foreach (MemberInfo m in ms) {
		Console.WriteLine(m);
	}
}
C# VB  

运行该示例时您将注意到,同时会发生其他一些事情。不必硬编码 System.String 对象,可以指定要获取有关哪个类的信息。它还使您可以控制是要显示静态信息还是实例信息。

posted @ 2005-03-11 17:31 HAL9000 阅读(1017) | 评论 (0)编辑

如何获取程序集内的类型

本示例阐释如何检索给定程序集的所有类型。若要浏览程序集的类型,首先需要标识想操作的程序集。在使某对象引用了感兴趣的程序集后,可以在该程序集上调用 GetTypes 方法,它返回包含该程序集内所有类型的一个数组。您可以使用控制逻辑标识该数组中的更具体类型,并使用迭代逻辑分析您的数组,在需要时向用户返回类型信息。检索类型信息的功能对确定可用于给定任务的其他类型很有用,或对标识可为您提供所需功能的现有元素很有用。

 
C# GetTypes.aspx

[运行示例] | [查看源代码]

从特定程序集检索类型时要学习的首要内容是如何标识程序集。本"快速入门"展示检索程序集的两种方法。第一种方法是标识要在程序集内查找的特定对象,并向程序集请求该对象的模块(记住模块是类型和代码的逻辑分组,如 .dll 或 .exe)。第二种方法是使用 Assembly 类的 LoadFrom 方法,为指定模块(如 myapp.exe)加载特定程序集。

// don't forget your using statements
using System;
using System.Reflection;
// ...

// Getting an Assembly, method 1. Get the mscorlib assembly
// Note that other types such as String, or Int32 would have worked just as well,
// since they reside in the same assembly
Assembly a = typeof(Object).Module.Assembly;

// Getting an Assembly, method 2. Load a particular assembly, using a reference to a
// module that is within that assembly. Note that this requires a compiled module for
// the reference, and when running in an aspx page, will require a fully qualifed path
// to the file, to ensure it is correctly identified
Assembly b = Assembly.LoadFrom ("GetTypes.exe");

// note that either of the above methods is viable, depending on the information
// you have. Since we know the name of the file which houses all of the base system
// objects, we could do the following to replace the first example, just as effectively
// (the absolute path may change on your machine)
// Assembly a = Assembly.LoadFrom
//			("c:/winserv/microsoft.net/framework/v1.0.2230/mscorlib.dll");
C# VB  

标识了程序集后,现在可以继续检索类型,将 GetTypes 方法的返回值分配给 Type 对象的数组。现在便可以操作这些类型了。在下面的示例中,您将获取核心运行时库的类型,并分别计算该程序集内不同类型样式的数目(如果需要有关 Foreach (For Each) 语句的更多信息,请参阅如何迭代通过集合主题下的内容)。尽管还可以计算其他成员(如类和枚举)的数目,但在该示例中,将只展示如何计算接口数目。

//Get all the types in the assembly identified in the previous example
Type [] types = a.GetTypes ();

int numInterfaces = 0;



foreach (Type t in types) {

	//the following line uses a set of methods which identify what
	//kind of type we are currently querying
	if (t.IsInterface) {
		// only print out the names of the Interfaces
		Console.WriteLine (t.Name + "");
		numInterfaces++;
	}
}

// write out the totals
Console.WriteLine("Out of {0} types in the {1} library:",
			types.Length, typeof(Object).Module.ToString());
Console.WriteLine ("{0} are interfaces (listed)", types.Length, numInterfaces);
C#