- C#实际选择 STK11版本 or STK12版本的问题备注。
【 C# 自动化客户端调用 STK 时,实际选择 STK11 版本 or STK12 版本 的调试运行备注】
以下代码"更新并重新打包备份为"〔testSTKQualNetInterface备份08.1_★避坑★【种子卫星:天线直接安装在卫星上,中间不能有Sensor传感器】.zip〕
源码文件: g:\teststkqualnetinterface\starlinksimulationclient.cs
private void button_OpenSTK_Click(object sender, EventArgs e)
{
#region 打开STK引擎:首先尝试打开现有STK软件,没有现成打开的STK;则新建打开一个STK软件实例
try
{//尝试获取现在已经在运行的 STK实例
m_uiApp = System.Runtime.InteropServices.Marshal.GetActiveObject("STK11.Application") as AgUiApplication;
#region C#自动化客户端调用STK时,实际选择 STK11版本 or STK12版本 的调试运行备注 @2024-5-7 09:16:28
// 貌似上面的 GetActiveObject("STK11.Application") 指定调用 STK11版本,
// 其实不是,真正决定C#调用哪个版本的的STK,即【实际选择 STK11版本 or STK12版本】,
// 是由【[testSTKQualNetInterface]】C#工程里引用的[AGI.STKObjects.Interop]系列【.Net互操作程序集】的STK版本决定的!
// 比如,目前这个工程引用的[AGI.STKObjects.Interop.dll]是 12.0.0.0,那么运行时调用的就是 STK12版本
// 所以,貌似 GetActiveObject("STK11.Application") 中的 "STK11.Application" 对 STK11版本 or STK12版本 都适用。
#endregion C#自动化客户端调用STK时,实际选择 STK11版本 or STK12版本 的调试运行备注
- 将〔testSTKQualNetInterface备份08.1_★避坑★【种子卫星:天线直接安装在卫星上,中间不能有Sensor传感器】.zip〕中的《 Program.cs StarlinkSimulationClient.cs StarlinkSimulationClient.Designer.cs XLsatNPF.cs 》源码文件重新替换到〔F:\WS_STK_use_Interop\test_Client 〕解决方案中的'testSTKQualNetInterface'工程中,调试运行:
- 编译通过、运行正常,未报错;
- '一键自动化测试',最后一步是调用[button_SaveToVDF_Click]加密保存场景为*.vdf,密码为 roottoor ;
- 调试运行时,C#调用STK11.6正常;保存的[D:\Temp\Starlink5x4_20SAT-SimScenario.vdf],既能用 STK11.6 也能用 STK12.2 打开(密码roottoor);
【 STK11.6 逆向编译生成的 Exata 插件,测试运行正常 → 卫星节点位置可以正常调用 STK 进行更新】★ STK+Exata 联合仿真★
-
- 【STK11.6逆向编译生成的Exata插件,测试运行正常】用STK11.6重新打开加密保存的[D:\Temp\Starlink5x4_20SAT-SimScenario.vdf],调出'软件逆向(反编译后重新编译)JSLS生成的'【QualNet Interface】场景管理器,对卫星Antenna天线建立网络连接并且建立星间链路,再在【QualNet Interface】场景管理器里单击'go',能够正常调用Exata进行网络仿真!
- STK11.6调用Exata插件进行网络仿真,生成的仿真*.config配置文件及目录,可以正常用Exata7.3打开(Exata6.2设置了调试断点会报错),卫星节点位置可以正常调用 STK 进行更新!
- 因为【QualNet Interface Scenario Explorer】场景管理器,本质上在操作时,是调用'作为组件服务 的[AGI.StkQualnetUiControls ]++服务器'++,所以跟踪调试的时候:
★客户端服务器 CS 模式 调试运行 【 QualNet Interface Scenario Explorer 】场景管理器 STK.Net 组件插件 ★
-
- 首先还是运行【[F:\WS_STK_use_Interop\test_Client]】解决方案里的"C#客户端",单击'一键自动化测试',等待C#客户端操作STK服务器,创建仿真场景完毕;
- 然后打开【[F:\WS_STK_use_Interop\test_Server]】解决方案,:
- 第三,在打开的【[F:\WS_STK_use_Interop\test_Server ]】解决方案中,附加到进程,++附加到++ ++[AgUiApplication.exe]STK++ ++软件进程++;
- 在【[F:\WS_STK_use_Interop\test_Server ]】解决方案的《NetworkInterfaceForm.cs》(位于[F:\WS_STK_use_Interop\test_Server\AGI.StkQualnetUiControls\]工程),找到构造函数,下断点以便跟踪调试;
public NetworkInterfaceForm (NetworkInterface networkInterface, Entity parentEntity, AgStkObjectRoot stkRoot)
-
- 在【[test_Client ]】客户端解决方案运行的C#程序打开的STK11.6软件中,手动操作调出【QualNet Interface Scenario Explorer】场景管理器,选定某颗卫星(比如XL11),右键'Add',目的是为该卫星添加网络接口Interface; è 马上可以发现【[test_Server ]】里的NetworkInterfaceForm (NetworkInterface networkInterface, Entity parentEntity, AgStkObjectRoot stkRoot)断点被拦截命中,这时的调用堆栈是:
> AGI.StkQualnetUiControls.dll!AGI.StkQualnetUiControls.NetworkInterfaceForm .NetworkInterfaceForm(AGI.StkQualnetObjectModel.NetworkInterface networkInterface, AGI.StkQualnetObjectModel.Entity parentEntity, AGI.STKObjects.AgStkObjectRoot stkRoot) 行 24 C#
AGI.StkQualnetUiControls.dll!AGI.StkQualnetUiControls.StkQualnetScenarioExplorer.OnEntityAddNetworkInterfaceMenuItemClick(object sender, System.EventArgs e) 行 253 C#
AGI.StkQualnetUiControls.dll!AGI.StkQualnetUiControls.StkQualnetScenarioExplorer.networkInterfacesContextMenuAdd_Click(object sender, System.EventArgs e) 行 266 C#
- 经跟踪调试,锁定【QualNet Interface Scenario Explorer】场景管理器'针对Antenna天线添加Interface网络接口'的关键代码:
★调试找到关键代码★【场景管理器'针对 Antenna 天线添加 Interface 网络接口'】
-
- 【《 F:\WS_STK_use_Interop\test_Server\AGI.StkQualnetUiControls\StkQualnetScenarioExplorer.cs 》 】的[OnEntityAddNetworkInterfaceMenuItemClick ],其中,两句最关键的是【 new NetworkInterfaceForm(null, entityTreeNode.Entity, this.StkRoot); 】和【 NetworkInterface networkInterface = networkInterfaceForm.GetNetworkInterface(); 】;
- 【《 F:\WS_STK_use_Interop\test_Server\AGI.StkQualnetUiControls\NetworkInterfaceForm.cs 》 】的[public NetworkInterface GetNetworkInterface()];
- 最终结果:对[AGI.StkQualnetObjectModel.NetworkInterface]类型的【[networkInterface] 类成员变量】进行赋值。
① 【《StkQualnetScenarioExplorer.cs》】的[ OnEntityAddNetworkInterfaceMenuItemClick ]:
源码如下:
private void OnEntityAddNetworkInterfaceMenuItemClick(object sender, EventArgs e)
{
EntityTreeNode entityTreeNode = this.EntityContextMenu.Tag as EntityTreeNode;
if (entityTreeNode != null && entityTreeNode.Entity != null)
{
NetworkInterfaceForm networkInterfaceForm = new NetworkInterfaceForm(null, entityTreeNode.Entity, this.StkRoot);
if (networkInterfaceForm.ShowDialog() == DialogResult.OK)
{
NetworkInterface networkInterface = networkInterfaceForm.GetNetworkInterface();
entityTreeNode.Entity.NetworkInterfaces.Add(networkInterface);
entityTreeNode.InterfacesNode.Nodes.Add(new NetworkInterfaceTreeNode(networkInterface));
}
}
}
② 【《NetworkInterfaceForm.cs》】的[ public NetworkInterface GetNetworkInterface() ]
源码如下:
public NetworkInterface GetNetworkInterface()
{
if (this.m_networkInterface == null)
{
this.m_networkInterface = new NetworkInterface(this.InterfaceName);
}
else
{
this.m_networkInterface.Name = this.InterfaceName;
}
IAgStkObject agStkObject = null;
if (this.transmitterInstanceNameCombo.SelectedIndex < 0)
{
IAgStkObject agStkObject2 = this.m_stkRoot.GetObjectFromPath(this.m_parentEntity.StkObjectPath.PathString);
if (this.useTransmitterSensor.Checked)
{
if (this.transmitterSensorCombo.SelectedIndex < 0)
{
try
{
agStkObject = (agStkObject2 = agStkObject2.Children.New(AgESTKObjectType.eSensor, this.transmitterSensorCombo.Text));
goto IL_B5;
}
catch
{
agStkObject2 = null;
goto IL_B5;
}
}
agStkObject2 = (this.transmitterSensorCombo.SelectedItem as ComboBoxItem).Item as IAgStkObject;
}
IL_B5:
try
{
if (agStkObject2 != null)
{
IAgStkObject agStkObject3 = agStkObject2.Children.New(AgESTKObjectType.eAntenna, this.transmitterInstanceNameCombo.Text);
this.m_networkInterface.TransmitAntennaStkPath = agStkObject3.Path;
}
goto IL_11E;
}
catch
{
goto IL_11E;
}
}
IAgStkObject agStkObject4 = (this.transmitterInstanceNameCombo.SelectedItem as ComboBoxItem).Item as IAgStkObject;
this.m_networkInterface.TransmitAntennaStkPath = agStkObject4.Path;
IL_11E:
if (this.useTransmitAntennaForReceiveCheckBox.Checked)
{
this.m_networkInterface.ReceiveAntennaStkPath = this.m_networkInterface.TransmitAntennaStkPath.PathString;
}
else
{
if (this.receiverInstanceNameCombo.SelectedIndex < 0)
{
IAgStkObject agStkObject5 = this.m_stkRoot.GetObjectFromPath(this.m_parentEntity.StkObjectPath.PathString);
if (this.useReceiverSensor.Checked)
{
if (this.receiverSensorCombo.SelectedIndex < 0)
{
try
{
if (agStkObject != null && this.receiverSensorCombo.Text.Equals(this.transmitterSensorCombo.Text))
{
agStkObject5 = agStkObject;
}
else
{
agStkObject5 = agStkObject5.Children.New(AgESTKObjectType.eSensor, this.receiverSensorCombo.Text);
}
goto IL_200;
}
catch
{
agStkObject5 = null;
goto IL_200;
}
}
agStkObject5 = (this.receiverSensorCombo.SelectedItem as ComboBoxItem).Item as IAgStkObject;
}
IL_200:
try
{
if (agStkObject5 != null)
{
IAgStkObject agStkObject6 = agStkObject5.Children.New(AgESTKObjectType.eAntenna, this.receiverInstanceNameCombo.Text);
this.m_networkInterface.ReceiveAntennaStkPath = agStkObject6.Path;
}
goto IL_26F;
}
catch
{
goto IL_26F;
}
}
IAgStkObject agStkObject7 = (this.receiverInstanceNameCombo.SelectedItem as ComboBoxItem).Item as IAgStkObject;
this.m_networkInterface.ReceiveAntennaStkPath = agStkObject7.Path;
}
IL_26F:
return this.m_networkInterface;
}
③[AGI.StkQualnetObjectModel.NetworkInterface]类型的【[networkInterface]类成员变量】调试时,内部变量赋值情况
- networkInterface {interface0} AGI.StkQualnetObjectModel.NetworkInterface
AGI.StkQualnetObjectModel.ISTKQualNetMappingWriterInterface.RainOutagePercent 0.1 double
ChannelIndex -1 int
+ IPv4Address {169.0.0.0} AGI.StkQualnetObjectModel.IPv4Address
+ IPv4SubnetMask {255.255.255.0} AGI.StkQualnetObjectModel.IPv4SubnetMask
IPv6Address null AGI.StkQualnetObjectModel.IPv6Address
IPv6SubnetMask null AGI.StkQualnetObjectModel.IPv6SubnetMask
- Id {444ff6ea-ac23-472a-be0b-0e28797a73c8} System.Guid
InterfaceId -1 int
IsNodeExpanded false bool
IsSatelliteInterface false bool
Link null AGI.StkQualnetObjectModel.IConnection
Name "interface0" string
NameWithParent "interface0" string
NetworkProtocol eIPv4 AGI.StkQualnetObjectModel.NetworkProtocolType
Parent null AGI.StkQualnetObjectModel.NetworkInterfaceList
PropertyChanged null System.ComponentModel.PropertyChangedEventHandler
QualNetInterfaceId "-1" string
- RainOutagePercent {AGI.StkQualnetObjectModel.VariableDouble} AGI.StkQualnetObjectModel.VariableDouble
+ ReceiveAntennaStkPath {/Satellite/XL11/Antenna/antennaU1} AGI.StkQualnetObjectModel.StkObjectPath
STKReceiveAntennaPath "/Application/STK/Scenario/StarlinkSimScenario/Satellite/XL11/Antenna/antennaU1" string
STKTransmitAntennaPath "/Application/STK/Scenario/StarlinkSimScenario/Satellite/XL11/Antenna/antennaU1" string
- Subcategory {AGI.StkQualnetObjectModel.NetworkInterfaceSubcategory} AGI.StkQualnetObjectModel.NetworkInterfaceSubcategory
+ TransmitAntennaStkPath {/Satellite/XL11/Antenna/antennaU1} AGI.StkQualnetObjectModel.StkObjectPath
-
m_id {AGI.StkQualnetObjectModel.VariableGuid} AGI.StkQualnetObjectModel.VariableGuid
-
m_idVariable {AGI.StkQualnetObjectModel.VariableInterfaceId} AGI.StkQualnetObjectModel.VariableInterfaceId
m_link null AGI.StkQualnetObjectModel.IConnection
m_name "interface0" string
m_parent null AGI.StkQualnetObjectModel.NetworkInterfaceList
-
m_receiveAntennaPath {AGI.StkQualnetObjectModel.VariableStkObjectPath} AGI.StkQualnetObjectModel.VariableStkObjectPath
-
m_transmitAntennaPath {AGI.StkQualnetObjectModel.VariableStkObjectPath} AGI.StkQualnetObjectModel.VariableStkObjectPath
-
Static members
AGI.StkQualnetUiControls.dll!AGI.StkQualnetUiControls.StkQualnetScenarioExplorer.OnEntityAddNetworkInterfaceMenuItemClick(object sender, System.EventArgs e) 行 253 C#
- 修改【反编译后重新编译报错的[AGI.StkQualnetObjectModel]】,并添加到[test_Client]解决方案,调整工程项目依赖顺序,编译成功:
★ [AGI.StkQualnetObjectModel] 逆向后编译成功★ →修改【反编译后重新编译报错的 [AGI.StkQualnetObjectModel] 】,并添加到 [test_Client] 解决方案,调整工程项目依赖顺序,编译成功
★【反编译导出为 VS2019****项目 】使用dnSpy v6.1.8 选择导出为VS2019 项目 ;
★【VS2022 打开反编译导出的项目】打开反编译的[AGI.StkQualnetObjectModel]VS2019****项目 ,修改编译报错的地方,其实大概就是几类报错问题(之前还是心理惧怕,以为很多错误^_^);
★【++VS2022++ ++修改++ [AGI.StkQualnetObjectModel]反编译后**++报错地方++**,编译成功】编译成功的代码打包备份在〔[F:\WS_STK_use_Interop\AGI.StkQualnetObjectModel 【 STK11.6 的 Exata 插件, dnSpy 逆向后重新编译成功 ^_^ 】 .zip ]〕 → 后来发现其实也可以用VS2015打开!!!;
★【将修改报错完毕的[AGI.StkQualnetObjectModel]添加到[test_Client]解决方案,调整工程项目依赖顺序,编译成功】编译成功的代码打包备份在〔[F:\WS_STK_use_Interop\test_Client 【成功编译 ^_^ 添加 [AGI.StkQualnetObjectModel] 逆向工程之后】 .zip ]〕。
★★★★★【VS2022修改[AGI.StkQualnetObjectModel]反编译后报错地方,编译成功】
①(string)element.Attribute("min"); 未赋值报错问题;
源码文件: F:\WS_STK_use_Interop\AGI.StkQualnetObjectModel\AGI.StkQualnetObjectModel\QualnetXmlHelper.cs
else if (text3.Equals("TEXT")) // JSLS备注: IPv6 地址格式
{
// JSLS备注: 下面的 dnSpy 反编译源码 重新编译 报错
//(string)element.Attribute("min");
//(string)element.Attribute("max");
string strJSLS_min = (string)element.Attribute("min");
string strJSLS_max = (string)element.Attribute("max");
if (text.ToUpper().Contains("V6-ADDRESS")) // JSLS备注: IPv6 地址格式
{
if (text5.Length == 0)
{
text5 = "2000::"; // JSLS备注: IPv6 地址格式
}
result = new VariableIPv6Address(text2, text, text7, flag2, text6, text9, text8, optional, text5);
}
else
{
result = new VariableString(text2, text, text7, flag2, text6, text9, text8, optional, text5);
}
}
② using(){ while() } 改为 foreach() 迭代问题;
源码文件:F:\WS_STK_use_Interop\AGI.StkQualnetObjectModel\AGI.StkQualnetObjectModel\Scenario.cs
// Token: 0x060003D1 RID: 977 RVA: 0x00010A18 File Offset: 0x0000EC18
public static void ImportFromStkScenario(AgScenario stkScenario, Scenario newScenario)
{
newScenario.StkRoot = (stkScenario.Root as AgStkObjectRoot);
foreach (object obj in stkScenario.Children)
{
IAgStkObject agStkObject = (IAgStkObject)obj;
Entity entity;
if (agStkObject.ClassType == AgESTKObjectType.eMissileSystem)
{
// JSLS备注: 下面的 dnSpy 反编译原始代码,报错!
// 【错误 CS1674 "IEnumerator": using 语句中使用的类型必须可隐式转换为"System.IDisposable" AGI.StkQualnetObjectModel D:\Intel\11111\AGI.StkQualnetObjectModel\Scenario.cs】
//using (IEnumerator enumerator2 = agStkObject.Children.GetEnumerator())
// JSLS分析:查看阅读 STK 编程帮助文档, STK编程中, foreach() 迭代方式用得多一些!
// using (IEnumerator enumerator2 = agStkObject.Children.GetEnumerator())
// 加上 while (enumerator2.MoveNext())
// 实际上应该就是【 foreach(IAgStkObject obj2 in iagObjectItems) 】迭代方式?
IAgStkObjectCollection iagObjectItems = agStkObject.Children;
foreach(IAgStkObject obj2 in iagObjectItems)
{
//while (enumerator2.MoveNext())
//{
//object obj2 = enumerator2.Current;
IAgStkObject stkObject = (IAgStkObject)obj2;
entity = Scenario.CreateEntityFromStkObject(newScenario, stkObject);
if (entity != null && entity != null)
{
newScenario.Hierarchy.Entities.Add(entity);
}
//}
//continue;
}
}
entity = Scenario.CreateEntityFromStkObject(newScenario, agStkObject);
if (entity != null && entity != null)
{
newScenario.Hierarchy.Entities.Add(entity);
}
}
}
③ yield return 问题;
源码文件: F:\WS_STK_use_Interop\AGI.StkQualnetObjectModel\AGI.StkQualnetObjectModel\Node.cs
// Token: 0x060002EC RID: 748 RVA: 0x00009D26 File Offset: 0x00007F26
public IEnumerator<Element> GetDepthFirstEnumerator()
{
yield return this.mData;
foreach (Node<Element> node in this.mChildren)
{
IEnumerator<Element> kidenumerator = node.GetDepthFirstEnumerator();
while (kidenumerator.MoveNext())
{
// 下面 dnSpy 反编译的代码 重新编译报错
//!0! = kidenumerator.Current;
//yield return !;
// JSLS备注:不知道这个逻辑对不对?
this.mData = kidenumerator.Current;
yield return this.mData;
}
kidenumerator = null;
}
IEnumerator<Node<Element>> enumerator = null;
yield break;
yield break;
}
④ < PrivateImplementationDetails >.ComputeStringHash(type) 密封类问题;
源码文件: F:\WS_STK_use_Interop\AGI.StkQualnetObjectModel\AGI.StkQualnetObjectModel\QualNetAppConfigWriter.cs
// JSLS备注: 【 < PrivateImplementationDetails > 】应该是个密封类, 修改名字为【 [JSLS_XiaoYuHao__PrivateImplementationDetails__JSLS_DaYuHao] 】
internal sealed class JSLS_XiaoYuHao__PrivateImplementationDetails__JSLS_DaYuHao
{
// Token: 0x06000759 RID: 1881 RVA: 0x0001D0CC File Offset: 0x0001B2CC
internal static uint ComputeStringHash(string s)
{
uint num = 0U;
if (s != null)
{
num = 2166136261U;
for (int i = 0; i < s.Length; i++)
{
num = ((uint)s[i] ^ num) * 16777619U;
}
}
return num;
}
}
// Token: 0x0600030A RID: 778 RVA: 0x0000A01C File Offset: 0x0000821C
public bool Write()
{
if (this.m_scenario.Connections.Applications.Count > 0 && !File.Exists(this.FilePath))
{
try
{
this.m_writer = File.CreateText(this.FilePath);
this.m_writer.AutoFlush = true;
foreach (NetworkApplication networkApplication in this.m_scenario.Connections.Applications)
{
this.WriteFormattedString("{0} {1} {2} ", new object[]
{
networkApplication.Type,
networkApplication.Source.NodeId,
networkApplication.Destination.NodeId
});
string type = networkApplication.Type;
// JSLS备注: 【 < PrivateImplementationDetails > 】应该是个密封类, 修改名字为【 [JSLS_XiaoYuHao__PrivateImplementationDetails__JSLS_DaYuHao] 】
//uint num = < PrivateImplementationDetails >.ComputeStringHash(type);
uint num = JSLS_XiaoYuHao__PrivateImplementationDetails__JSLS_DaYuHao.ComputeStringHash(type);
if (num <= 2037514399U)
{
if (num <= 893884390U)
{
if (num != 563683786U)
{
if (num != 570659453U)
{
if (num == 893884390U)
{
if (type == "CBR")
{
this.WriteCBR(networkApplication);
}
}
}
else if (type == "TELNET")
⑤ ★★ Func<T, TResult>() 委托类型函数声明问题;
源码文件: F:\WS_STK_use_Interop\AGI.StkQualnetObjectModel\AGI.StkQualnetObjectModel\QualnetConfigFileMapping \ConfigFileInfo.cs
#region JSLS备注: 【 Func<NodeInfo, bool> 委托名称 】,表示输入为[NodeInfo]类型、输出为[bool]类型,名字叫[委托名称]的委托!
/*
以下示例所演示的那样将 lambda 表达式分配给 Func<T, TResult>委托。
using System;
public class LambdaExpression
{
public static void Main()
{
Func<string, string> convert = s => s.ToUpper();
string name = "Dakota";
Console.WriteLine(convert(name));
}
}
*/
#endregion JSLS备注: 【 Func<NodeInfo, bool> 委托名称 】,表示输入为[NodeInfo]类型、输出为[bool]类型,名字叫[委托名称]的委托!
//Func<NodeInfo, bool> <>9__1;
// JSLS备注: 声明一个 目前为空的【委托】
// 参考:VS2010帮助《Func<TResult> 委托》
#region 参考 VS2010帮助《Func<TResult> 委托》 中 的最后一个例子
/*
using System;
static class Func1
{
public static void Main()
{
// Note that each lambda expression has no parameters.
LazyValue<int> lazyOne = new LazyValue<int>(() => ExpensiveOne());
LazyValue<long> lazyTwo = new LazyValue<long>(() => ExpensiveTwo("apple"));
Console.WriteLine("LazyValue objects have been created.");
// Get the values of the LazyValue objects.
Console.WriteLine(lazyOne.Value);
Console.WriteLine(lazyTwo.Value);
}
static int ExpensiveOne()
{
Console.WriteLine("\nExpensiveOne() is executing.");
return 1;
}
static long ExpensiveTwo(string input)
{
Console.WriteLine("\nExpensiveTwo() is executing.");
return (long)input.Length;
}
}
class LazyValue<T> where T : struct
{
private Nullable<T> val;
private Func<T> getValue;
// Constructor.
public LazyValue(Func<T> func)
{
val = null;
getValue = func;
}
public T Value
{
get
{
if (val == null)
// Execute the delegate.
val = getValue();
return (T)val;
}
}
}
*/
#endregion 参考 VS2010帮助《Func<TResult> 委托》 中 的最后一个例子
Func<NodeInfo, bool> JSLSdebug__DaYuXiaoYu9__1 = new Func<NodeInfo, bool>( (nodeInfo) => (false) );
// 【空委托】的写法: 右箭头的 左边 [nodeInfo] 表示输入类型为[NodeInfo]的形参,右箭头的 右边[false] 表示 委托函数实现时返回 bool 类型的 值 false 。
//Func<NodeInfo, bool> <>9__3;
Func<NodeInfo, bool> JSLSdebug__DaYuXiaoYu9__3 = new Func<NodeInfo, bool>( (nodeInfo) => (false) );
// 【空委托】的写法: 右箭头的 左边 [nodeInfo] 表示输入类型为[NodeInfo]的形参,右箭头的 右边[false] 表示 委托函数实现时返回 bool 类型的 值 false 。
foreach (string text2 in match.Value.Substring(num2 + 1, num3 - num2 - 1).Split(new char[]
{
','
}))
{
List<string> list3 = new List<string>();
if (text2.ToUpper().Contains("THRU"))
{
string text3 = text2.ToUpper();
int num4 = text3.IndexOf('T');
int num5 = text3.IndexOf('U');
string s = text3.Substring(0, num4 - 1).Trim();
string s2 = text3.Substring(num5 + 1).Trim();
int num6;
int.TryParse(s, out num6);
int num7;
int.TryParse(s2, out num7);
for (int j = num6; j <= num7; j++)
{
list3.Add(j.ToString());
}
}
else
{
list3.Add(text2);
}
foreach (string text4 in list3)
{
bool flag = false;
string trimmedCurId = text4.Trim();
long num8 = long.Parse(trimmedCurId);
string pattern4 = string.Format(ConfigFileInfo.s_satelliteNodeSearchPattern, trimmedCurId);
if (Regex.Match(configText, pattern4).Success)
{
IEnumerable<NodeInfo> nodeInfo = this.m_nodeInfo;
Func<NodeInfo, bool> predicate;
// 假如 predicate 委托函数 为空的话
if ((predicate = /*<>9__1*/ JSLSdebug__DaYuXiaoYu9__1) == null)
{
predicate = (/*<>9__1*/ JSLSdebug__DaYuXiaoYu9__1 = ((NodeInfo n) => n.Subnet.Equals(subnet) && n.IsSatellite));
// JSLS备注: 【 Func<NodeInfo, bool> 委托名称 】,表示输入为[NodeInfo]类型、输出为[bool]类型,名字叫[委托名称]的委托!
/*
以下示例所演示的那样将 lambda 表达式分配给 Func<T, TResult>委托。
using System;
public class LambdaExpression
{
public static void Main()
{
Func<string, string> convert = s => s.ToUpper();
string name = "Dakota";
Console.WriteLine(convert(name));
}
}
*/
}
if (new List<NodeInfo>(nodeInfo.Where(predicate)).Count == 0)
{
flag = true;
}
}
★★★★★【将修改报错完毕的[AGI.StkQualnetObjectModel]添加到[test_Client] 解决方案,调整工程项目依赖顺序,编译成功】
重点需要注意:
①被依赖项目编译后 *.dll 输出目录设置问题:具体在【某个工程项目】右键 → 属性 → 生成 → 输出 → 将【输出路径】设置为 STK11.6 的 Exata .Net DLL组件插件目录位置,即【[ C:\Program Files\AGI\STK 11\STK-QualNet Interface\ ]】
②项目依赖设置问题:特别注意,不仅要右键'解决方案'选择[项目依赖项]、[项目生成顺序]进行设置;而且,还要记得,对'每个具体的工程项目' ,再右键选择[生成依赖项]→[项目依赖项]、[项目生成顺序]进行设置。