如何在C#.NET中实现类似VBScript的对象复用逻辑
PCOMM会话管理VBS转C#的问题与解决
问题描述
原本用VBScript开发了一套PCOMM会话管理方案:动态销毁并复用AutSess对象,排除生产会话("A"会话)及登录特定业务应用(窗口标题含"HOSTORS"或"NDB")的会话,仅使用可用会话。
迁移至C#.NET后编写了逻辑相似的代码,遇到两个问题:
- 尝试在循环内重新声明
AutSess ObjEmulator = new AutSess();时触发CS0136错误(命名冲突) - C#中
ObjEmulator = null无法像VBScript的Set ObjEmulator = Nothing那样彻底销毁COM对象
原VBScript代码
Set Connect_Manager = CreateObject("pcomm.autECLConnMgr") Set autECLConnList = CreateObject("PCOMM.autECLConnList") Set ObjEmulator = CreateObject("pcomm.auteclsession") autECLConnList.Refresh Num = autECLConnList.Count PrevNum = Num If Num = 0 Then MsgBox "You must have at least two PCOMM sessions open to use this tool." & vbnewline & vbnewline & "Program is now terminating.", vbOKOnly + vbExclamation + vbSystemModal, "No Session Error" SetEverythingToNothing WScript.Echo "EXIT" WScript.Quit End If strSession = autECLConnList(Num).Name Connect_Manager.autECLConnList.Refresh ObjEmulator.SetConnectionByName (strSession) Window_Title = ObjEmulator.autECLWinMetrics.WindowTitle If InStr(Window_Title, "HOSTORS") <> 0 Or strSession = "A" Or InStr(Window_Title, "NDB") <> 0 Then Set ObjEmulator = Nothing Loop_Count = 1 Do ResEmulator = "No" PrevNum = PrevNum - 1 If PrevNum = 0 Then MsgBox "You need to have more than one session open." & vbnewline & "Program is now terminating.", vbOKOnly + vbExclamation + vbSystemModal, "One Session Error" SetEverythingToNothing WScript.Echo "EXIT" WScript.Quit Else strSession = autECLConnList(PrevNum).Name If strSession = "A" Then MsgBox "You cannot use your production (A) session." & vbnewline & "Please open another session." & vbnewline & "Program is now terminating.", vbOKOnly + vbExclamation + vbSystemModal, "Production Session Error" SetEverythingToNothing WScript.Echo "EXIT" WScript.Quit Exit Do Else Set ObjEmulator = CreateObject("pcomm.auteclsession") Connect_Manager.autECLConnList.Refresh ObjEmulator.SetConnectionByName (strSession) Window_Title = ObjEmulator.autECLWinMetrics.WindowTitle If InStr(Window_Title, "NDB") <> 0 Or InStr(Window_Title, "HOSTORS") <> 0 Then Set ObjEmulator = Nothing Else ResEmulator = "Yes" End If End If End If Loop_Count = Loop_Count + 1 If Loop_Count = 10 Then MsgBox "Unable to connect to a session." & vbnewline & "Please make sure you have working sessions." & vbnewline & "Program is now terminating.", vbOKOnly + vbExclamation + vbSystemModal, "Production Session Error" SetEverythingToNothing WScript.Echo "EXIT" WScript.Quit Exit Do End If Loop Until ResEmulator = "Yes" End If
改写后的C#代码(存在问题版本)
AutConnList autECLConnList = new AutConnList(); AutConnMgr Connect_Manager = new AutConnMgr(); AutSess ObjEmulator = new AutSess(); autECLConnList.Refresh(); int Num = autECLConnList.Count; int PrevNum = Num; if (Num == 0) { MessageBox.Show("You must have at least two PCOMM sessions open to use this tool." + Environment.NewLine + Environment.NewLine + "Program is now terminating.", "No Session Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1, MessageBoxOptions.DefaultDesktopOnly); return; } string strSession = autECLConnList[Num].Name; autECLConnList.Refresh(); ObjEmulator.SetConnectionByName(strSession); string Window_Title = ObjEmulator.autECLWinMetrics.WindowTitle; if (Window_Title.IndexOf("HOSTORS") == 0 || strSession == "A" || Window_Title.IndexOf("NDB") == 0) { ObjEmulator = null; int Loop_Count = 1; string ResEmulator = "No"; do { PrevNum -= 1; if (PrevNum == 0) { MessageBox.Show("You need to have more than one session open." + Environment.NewLine + "Program is now terminating.", "One Session Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1, MessageBoxOptions.DefaultDesktopOnly); return; } else { strSession = autECLConnList[PrevNum].Name; if (strSession == "A") { MessageBox.Show("You cannot use your production (A) session." + Environment.NewLine + "Please open another session." + Environment.NewLine + "Program is now terminating.", "Production Session Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1, MessageBoxOptions.DefaultDesktopOnly); return; } else { ObjEmulator = new AutSess(); autECLConnList.Refresh(); ObjEmulator.SetConnectionByName(strSession); Window_Title = ObjEmulator.autECLWinMetrics.WindowTitle; if (Window_Title.IndexOf("HOSTORS") == 0 || Window_Title.IndexOf("NDB") == 0) { ObjEmulator = null; } else { ResEmulator = "Yes"; } } } Loop_Count++; if (Loop_Count == 10) { MessageBox.Show("Unable to connect to a session." + Environment.NewLine + "Please make sure you have working sessions." + Environment.NewLine + "Program is now terminating.", "Production Session Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1, MessageBoxOptions.DefaultDesktopOnly); return; } } while (ResEmulator == "Yes"); }
解决方案
1. 解决CS0136命名冲突错误
CS0136是因为在同一作用域内重复声明同名变量。C#不允许在同一作用域内多次声明相同名称的变量,只需要去掉重复的声明语句,直接对已声明的变量重新赋值即可:
- 把循环内的
AutSess ObjEmulator = new AutSess();改为ObjEmulator = new AutSess();(变量ObjEmulator已经在方法顶部声明过)
2. 实现COM对象的彻底销毁
PCOMM的AutSess是COM互操作对象,仅设置ObjEmulator = null只是断开C#对它的引用,COM侧的资源不会立即释放。要实现类似VBScriptSet ObjEmulator = Nothing的效果,需要:
- 先检查对象是否实现
IDisposable接口,若实现则调用Dispose() - 对于COM对象,调用
Marshal.ReleaseComObject()强制释放COM引用,确保资源回收
示例代码:
// 销毁AutSess对象的方法 private void ReleaseEmulator(AutSess emulator) { if (emulator != null) { // 如果实现了IDisposable,先调用Dispose if (emulator is IDisposable disposable) { disposable.Dispose(); } // 强制释放COM引用 System.Runtime.InteropServices.Marshal.ReleaseComObject(emulator); } }
在需要销毁对象的地方调用该方法:
// 替换原有的ObjEmulator = null ReleaseEmulator(ObjEmulator); ObjEmulator = null;
修正后的核心循环逻辑
if (Window_Title.IndexOf("HOSTORS") != -1 || strSession == "A" || Window_Title.IndexOf("NDB") != -1) { ReleaseEmulator(ObjEmulator); ObjEmulator = null; int Loop_Count = 1; string ResEmulator = "No"; do { PrevNum -= 1; if (PrevNum == 0) { MessageBox.Show("You need to have more than one session open." + Environment.NewLine + "Program is now terminating.", "One Session Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1, MessageBoxOptions.DefaultDesktopOnly); // 退出前释放所有资源 ReleaseEmulator(ObjEmulator); return; } else { strSession = autECLConnList[PrevNum].Name; if (strSession == "A") { MessageBox.Show("You cannot use your production (A) session." + Environment.NewLine + "Please open another session." + Environment.NewLine + "Program is now terminating.", "Production Session Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1, MessageBoxOptions.DefaultDesktopOnly); ReleaseEmulator(ObjEmulator); return; } else { // 先释放旧对象再创建新对象 ReleaseEmulator(ObjEmulator); ObjEmulator = new AutSess(); autECLConnList.Refresh(); ObjEmulator.SetConnectionByName(strSession); Window_Title = ObjEmulator.autECLWinMetrics.WindowTitle; if (Window_Title.IndexOf("HOSTORS") != -1 || Window_Title.IndexOf("NDB") != -1) { ReleaseEmulator(ObjEmulator); ObjEmulator = null; } else { ResEmulator = "Yes"; } } } Loop_Count++; if (Loop_Count == 10) { MessageBox.Show("Unable to connect to a session." + Environment.NewLine + "Please make sure you have working sessions." + Environment.NewLine + "Program is now terminating.", "Production Session Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1, MessageBoxOptions.DefaultDesktopOnly); ReleaseEmulator(ObjEmulator); return; } } while (ResEmulator != "Yes"); // 修正循环条件,原代码逻辑错误:应该是ResEmulator != "Yes"时继续循环 }
注意:原C#代码中的循环条件
while (ResEmulator == "Yes")是错误的,应该改为while (ResEmulator != "Yes"),否则会不符合原VBScript的逻辑。
内容的提问来源于stack exchange,提问作者Lou
相关产品推荐
相关产品推荐

