准备修改运行环境中类库的依赖结构

This commit is contained in:
fengjiayi
2024-11-03 18:28:16 +08:00
parent d646c4e820
commit a76091092d
15 changed files with 264 additions and 162 deletions

View File

@@ -138,15 +138,15 @@ namespace Serein.Library.Api
public class LoadDllEventArgs : FlowEventArgs
{
public LoadDllEventArgs(NodeLibrary nodeLibrary, List<MethodDetailsInfo> MethodDetailss)
public LoadDllEventArgs(NodeLibraryInfo nodeLibraryInfo, List<MethodDetailsInfo> MethodDetailss)
{
this.NodeLibrary = nodeLibrary;
this.NodeLibraryInfo = nodeLibraryInfo;
this.MethodDetailss = MethodDetailss;
}
/// <summary>
/// 已加载了的程序集
/// </summary>
public NodeLibrary NodeLibrary { get; protected set; }
public NodeLibraryInfo NodeLibraryInfo { get; protected set; }
/// <summary>
/// dll文件中有效的流程方法描述
/// </summary>
@@ -676,8 +676,8 @@ namespace Serein.Library.Api
/// <summary>
/// 移除DLL
/// </summary>
/// <param name="assemblyFullName">程序集的名称</param>
bool RemoteDll(string assemblyFullName);
/// <param name="assemblyName">程序集的名称</param>
bool RemoteDll(string assemblyName);
/// <summary>
/// 清理加载的DLL待更改

View File

@@ -1,34 +0,0 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
namespace Serein.Library
{
/// <summary>
/// 节点DLL依赖类如果一个项目中引入了多个DLL需要放置在同一个文件夹中
/// </summary>
public class NodeLibrary
{
/// <summary>
/// 文件名
/// </summary>
public string FileName { get; set; }
/// <summary>
/// 路径
/// </summary>
public string FilePath { get; set; }
/// <summary>
/// 依赖类的名称
/// </summary>
public string FullName{ get; set; }
/// <summary>
/// 对应的程序集
/// </summary>
public Assembly Assembly { get; set; }
}
}

View File

@@ -0,0 +1,108 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Text;
namespace Serein.Library
{
/// <summary>
/// 节点DLL依赖类如果一个项目中引入了多个DLL需要放置在同一个文件夹中
/// </summary>
public class NodeLibraryInfo
{
/// <summary>
/// 文件名
/// </summary>
public string FileName { get; set; }
/// <summary>
/// 路径
/// </summary>
public string FilePath { get; set; }
/// <summary>
/// 所属的程序集名称
/// </summary>
public string AssemblyName{ get; set; }
}
/// <summary>
///
/// </summary>
public class FlowLibrary
{
public FlowLibrary(string assemblyName,
Action actionOfUnloadAssmbly)
{
this.AssemblyName = assemblyName;
this.actionOfUnloadAssmbly = actionOfUnloadAssmbly;
}
public string AssemblyName { get; }
//public string AssemblyVersion { get; }
/// <summary>
/// 加载程序集时创建的方法描述
/// </summary>
public ConcurrentDictionary<string, MethodDetails> MethodDetailss { get; } = new ConcurrentDictionary<string, MethodDetails>();
/// <summary>
/// 管理通过Emit动态构建的委托
/// </summary>
public ConcurrentDictionary<string, DelegateDetails> DelegateDetailss { get; } = new ConcurrentDictionary<string, DelegateDetails>();
/// <summary>
/// 记录不同的注册时机需要自动创建全局唯一实例的类型信息
/// </summary>
public ConcurrentDictionary<RegisterSequence, Type[]> RegisterTypes { get; } = new ConcurrentDictionary<RegisterSequence, Type[]>();
private readonly Action actionOfUnloadAssmbly;
/// <summary>
/// 卸载当前程序集以及附带的所有信息
/// </summary>
public void Upload()
{
actionOfUnloadAssmbly?.Invoke();
}
/// <summary>
/// 通过方法名称获取对应的Emit委托元数据用于动态调用节点对应的方法
/// </summary>
/// <param name="methodName">方法名称</param>
/// <param name="dd">Emit委托</param>
/// <returns></returns>
public bool GetDelegateDetails(string methodName, out DelegateDetails dd)
{
return DelegateDetailss.TryGetValue(methodName, out dd);
}
/// <summary>
/// 通过方法名称获取对应的方法描述(元数据),用于创建节点时,节点实例需要的方法描述
/// </summary>
/// <param name="methodName">方法名称</param>
/// <param name="md">方法描述</param>
/// <returns></returns>
public bool GetMethodDetails(string methodName, out MethodDetails md)
{
return MethodDetailss.TryGetValue(methodName, out md);
}
public NodeLibraryInfo ToInfo()
{
return new NodeLibraryInfo
{
}
}
}
}

View File

@@ -129,7 +129,7 @@ namespace Serein.Library
&& index < ParameterDetailss.Length) // 防止下标越界
{
ParameterDetailss[index] = null; // 释放对象引用
var tmp = ArrayHelper.RemoteToArray(ParameterDetailss, index); // 新增;
var tmp = ArrayHelper.RemoteToArray<ParameterDetails>(ParameterDetailss, index); // 新增;
UpdateParamIndex(ref tmp);
ParameterDetailss = tmp; // 新增
return true;

View File

@@ -12,9 +12,9 @@ namespace Serein.Library
public class MethodDetailsInfo
{
/// <summary>
/// 属于哪个DLL文件
/// 属于哪个程序集
/// </summary>
public string LibraryName { get; set; }
public string AssemblyName { get; set; }
/// <summary>
/// 方法名称

View File

@@ -33,9 +33,9 @@ namespace Serein.Library
public class LibraryMds
{
/// <summary>
/// 程序集FullName
/// 程序集名称
/// </summary>
public string LibraryName { get; set; }
public string AssemblyName { get; set; }
/// <summary>
/// 相关的方法详情
/// </summary>

View File

@@ -2,8 +2,8 @@
<PropertyGroup>
<Version>1.0.19</Version>
<TargetFrameworks>net8.0;net462</TargetFrameworks>
<!--<TargetFrameworks>net8.0</TargetFrameworks>-->
<TargetFrameworks>net8.0;net462</TargetFrameworks>
<BaseOutputPath>D:\Project\C#\DynamicControl\SereinFlow\.Output</BaseOutputPath>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<Title>SereinFow</Title>
@@ -37,8 +37,6 @@
<ItemGroup>
<ProjectReference Include="..\Serein.Library.MyGenerator\Serein.Library.NodeGenerator.csproj" OutputItemType="Analyzer" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="System.Reactive" Version="6.0.1" />
<PackageReference Include="System.Threading.Channels" Version="8.0.0" />
@@ -60,4 +58,8 @@
</None>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Serein.Library.MyGenerator\Serein.Library.NodeGenerator.csproj " OutputItemType="Analyzer" />
</ItemGroup>
</Project>

View File

@@ -223,24 +223,45 @@ namespace Serein.NodeFlow.Env
#endregion
#region
/// <summary>
/// 通过程序集名称管理动态加载的程序集用于节点创建提供方法描述流程运行时提供Emit委托
/// </summary>
public ConcurrentDictionary<string, FlowLibrary> FlowLibrarys { get; } = [];
/// <summary>
/// Library 与 MethodDetailss的依赖关系
/// </summary>
public ConcurrentDictionary<NodeLibrary, List<MethodDetails>> MethodDetailsOfLibrarys { get; } = [];
public ConcurrentDictionary<NodeLibraryInfo, List<MethodDetails>> MethodDetailsOfLibraryInfos { get; } = [];
/// <summary>
/// 存储已加载的程序集
/// <para>存储已加载的程序集</para>
/// <para>Key程序集的FullName </para>
/// <para>Value构造的方法信息</para>
/// </summary>
public ConcurrentDictionary<string, NodeLibrary> Librarys { get; } = [];
public ConcurrentDictionary<string, NodeLibraryInfo> LibraryInfos { get; } = [];
/// <summary>
/// 存储已加载的方法信息。描述所有DLL中NodeAction特性的方法的原始副本
/// <para>存储已加载的方法信息。描述所有DLL中NodeAction特性的方法的原始副本</para>
/// <para>Key反射时获取的MethodInfo.MehtodName</para>
/// <para>Value构造的方法信息</para>
/// </summary>
public ConcurrentDictionary<string, MethodDetails> MethodDetailss { get; } = [];
/// <summary>
/// 容器管理
/// 从dll中加载的类的注册类型
/// </summary>
private Dictionary<RegisterSequence, List<Type>> AutoRegisterTypes { get; } = [];
/// <summary>
/// 存放所有通过Emit加载的委托
/// md.Methodname - delegate
/// </summary>
private ConcurrentDictionary<string, DelegateDetails> MethodDelegates { get; } = [];
/// <summary>
/// IOC对象容器管理
/// </summary>
private readonly SereinIOC sereinIOC;
@@ -255,18 +276,7 @@ namespace Serein.NodeFlow.Env
/// </summary>
private List<SingleFlipflopNode> FlipflopNodes { get; } = [];
/// <summary>
/// 从dll中加载的类的注册类型
/// </summary>
private Dictionary<RegisterSequence, List<Type>> AutoRegisterTypes { get; } = [];
/// <summary>
/// 存放委托
///
/// md.Methodname - delegate
/// </summary>
private ConcurrentDictionary<string, DelegateDetails> MethodDelegates { get; } = [];
/// <summary>
/// 起始节点私有属性
@@ -470,28 +480,28 @@ namespace Serein.NodeFlow.Env
/// <returns></returns>
public async Task<FlowEnvInfo> GetEnvInfoAsync()
{
Dictionary<NodeLibrary, List<MethodDetailsInfo>> LibraryMds = [];
Dictionary<NodeLibraryInfo, List<MethodDetailsInfo>> MdsOfLibraryInfos = [];
foreach (var mdskv in MethodDetailsOfLibrarys)
foreach (var mdskv in MethodDetailsOfLibraryInfos)
{
var library = mdskv.Key;
var mds = mdskv.Value;
foreach (var md in mds)
{
if (!LibraryMds.TryGetValue(library, out var t_mds))
if (!MdsOfLibraryInfos.TryGetValue(library, out var t_mds))
{
t_mds = new List<MethodDetailsInfo>();
LibraryMds[library] = t_mds;
MdsOfLibraryInfos[library] = t_mds;
}
var mdInfo = md.ToInfo();
mdInfo.LibraryName = library.FullName;
mdInfo.AssemblyName = library.AssemblyName;
t_mds.Add(mdInfo);
}
}
LibraryMds[] libraryMdss = LibraryMds.Select(kv => new LibraryMds
LibraryMds[] libraryMdss = MdsOfLibraryInfos.Select(kv => new LibraryMds
{
LibraryName = kv.Key.FullName,
AssemblyName = kv.Key.AssemblyName,
Mds = kv.Value.ToArray()
}).ToArray();
var project = await GetProjectInfoAsync();
@@ -716,7 +726,7 @@ namespace Serein.NodeFlow.Env
{
var projectData = new SereinProjectData()
{
Librarys = Librarys.Values.Select(lib => lib.ToLibrary()).ToArray(),
Librarys = LibraryInfos.Values.Select(lib => lib.ToLibrary()).ToArray(),
Nodes = NodeModels.Values.Select(node => node.ToInfo()).Where(info => info is not null).ToArray(),
StartNode = NodeModels.Values.FirstOrDefault(it => it.IsStart)?.Guid,
};
@@ -738,11 +748,11 @@ namespace Serein.NodeFlow.Env
/// <summary>
/// 移除DLL
/// </summary>
/// <param name="assemblyFullName"></param>
/// <param name="assemblyName"></param>
/// <returns></returns>
public bool RemoteDll(string assemblyFullName)
public bool RemoteDll(string assemblyName)
{
var library = Librarys.Values.FirstOrDefault(nl => assemblyFullName.Equals(nl.FullName));
var library = LibraryInfos.Values.FirstOrDefault(nl => assemblyName.Equals(nl.AssemblyName));
if (library is null)
{
return false;
@@ -761,7 +771,7 @@ namespace Serein.NodeFlow.Env
return true; // 当前无节点,可以直接删除
}
if (MethodDetailsOfLibrarys.TryGetValue(library, out var mds)) // 存在方法
if (MethodDetailsOfLibraryInfos.TryGetValue(library, out var mds)) // 存在方法
{
foreach (var md in mds)
{
@@ -778,7 +788,7 @@ namespace Serein.NodeFlow.Env
{
MethodDetailss.TryRemove(md.MethodName, out _);
}
MethodDetailsOfLibrarys.TryRemove(library, out _);
MethodDetailsOfLibraryInfos.TryRemove(library, out _);
return true;
}
else
@@ -1395,35 +1405,56 @@ namespace Serein.NodeFlow.Env
/// <param name="dllPath"></param>
private void LoadDllNodeInfo(string dllPath)
{
(var nodeLibrary, var registerTypes, var mdlist) = LoadAssembly(dllPath);
if (nodeLibrary is not null && mdlist.Count > 0)
var fileName = Path.GetFileName(dllPath);
AssemblyLoadContext flowAlc = new AssemblyLoadContext(fileName, true);
flowAlc.LoadFromAssemblyPath(dllPath); // 加载指定路径的程序集
foreach(var assemblt in flowAlc.Assemblies)
{
Librarys.TryAdd(nodeLibrary.FullName, nodeLibrary);
MethodDetailsOfLibrarys.TryAdd(nodeLibrary, mdlist);
foreach (var md in mdlist)
(var registerTypes, var mdlist) = LoadAssembly(assemblt);
if (mdlist.Count > 0)
{
MethodDetailss.TryAdd(md.MethodName, md);
}
foreach (var kv in registerTypes)
{
if (!AutoRegisterTypes.TryGetValue(kv.Key, out var types))
var nodeLibraryInfo = new NodeLibraryInfo
{
types = new List<Type>();
AutoRegisterTypes.Add(kv.Key, types);
//Assembly = assembly,
AssemblyName = assemblt.FullName,
FileName = Path.GetFileName(dllPath),
FilePath = dllPath,
};
LibraryInfos.TryAdd(nodeLibraryInfo.AssemblyName, nodeLibraryInfo);
MethodDetailsOfLibraryInfos.TryAdd(nodeLibraryInfo, mdlist);
foreach (var md in mdlist)
{
MethodDetailss.TryAdd(md.MethodName, md);
}
types.AddRange(kv.Value);
}
var mdInfos = mdlist.Select(md => md.ToInfo()).ToList(); // 转换成方法信息
if (OperatingSystem.IsWindows())
{
UIContextOperation?.Invoke(() => OnDllLoad?.Invoke(new LoadDllEventArgs(nodeLibrary, mdInfos))); // 通知UI创建dll面板显示
foreach (var kv in registerTypes)
{
if (!AutoRegisterTypes.TryGetValue(kv.Key, out var types))
{
types = new List<Type>();
AutoRegisterTypes.Add(kv.Key, types);
}
types.AddRange(kv.Value);
}
var mdInfos = mdlist.Select(md => md.ToInfo()).ToList(); // 转换成方法信息
if (OperatingSystem.IsWindows())
{
UIContextOperation?.Invoke(() => OnDllLoad?.Invoke(new LoadDllEventArgs(nodeLibraryInfo, mdInfos))); // 通知UI创建dll面板显示
}
}
}
}
/// <summary>
@@ -1477,18 +1508,17 @@ namespace Serein.NodeFlow.Env
}
/// <summary>
///
/// 动态加载程序集
/// </summary>
/// <param name="dllPath"></param>
/// <param name="assembly">程序集本身</param>
/// <returns></returns>
private (NodeLibrary?, Dictionary<RegisterSequence, List<Type>>, List<MethodDetails>) LoadAssembly(string dllPath)
private (Dictionary<RegisterSequence, List<Type>>, List<MethodDetails>) LoadAssembly(Assembly assembly)
{
try
{
//FlowLibraryLoader flowLibraryLoader = new FlowLibraryLoader(dllPath);
//Assembly assembly = flowLibraryLoader.LoadFromAssemblyPath(dllPath);
Assembly assembly = Assembly.LoadFrom(dllPath); // 加载DLL文件
List<Type> types = assembly.GetTypes().ToList(); // 获取程序集中的所有类型
#region
Dictionary<RegisterSequence, List<Type>> autoRegisterTypes = new Dictionary<RegisterSequence, List<Type>>();
foreach (Type type in types)
{
@@ -1504,25 +1534,29 @@ namespace Serein.NodeFlow.Env
}
}
#endregion
#region DynamicFlow
List<(Type, string)> scanTypes = types.Select(t =>
{
if (t.GetCustomAttribute<DynamicFlowAttribute>() is DynamicFlowAttribute dynamicFlowAttribute
&& dynamicFlowAttribute.Scan == true)
{
return (t, dynamicFlowAttribute.Name);
}
else
{
return (null, null);
}
}).Where(it => it.t is not null).ToList();
{
if (t.GetCustomAttribute<DynamicFlowAttribute>() is DynamicFlowAttribute dynamicFlowAttribute
&& dynamicFlowAttribute.Scan == true)
{
return (t, dynamicFlowAttribute.Name);
}
else
{
return (null, null);
}
}).Where(it => it.t is not null).ToList();
if (scanTypes.Count == 0)
{
return (null, [], []);
return ([], []);
}
#endregion
#region
List<MethodDetails> methodDetails = new List<MethodDetails>();
// 遍历扫描的类型
foreach ((var type, var flowName) in scanTypes)
@@ -1552,23 +1586,16 @@ namespace Serein.NodeFlow.Env
Console.WriteLine($"节点委托创建失败:{md.MethodName}");
}
}
}
}
#endregion
var nodeLibrary = new NodeLibrary
{
FullName = assembly.GetName().FullName,
Assembly = assembly,
FileName = Path.GetFileName(dllPath),
FilePath = dllPath,
};
//LoadedAssemblies.Add(assembly); // 将加载的程序集添加到列表中
//LoadedAssemblyPaths.Add(dllPath); // 记录加载的DLL路径
return (nodeLibrary, autoRegisterTypes, methodDetails);
return (autoRegisterTypes, methodDetails);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
return (null, [], []);
return ([], []);
}
}

View File

@@ -307,9 +307,9 @@ namespace Serein.NodeFlow.Env
}
public bool RemoteDll(string assemblyFullName)
public bool RemoteDll(string assemblyName)
{
return currentFlowEnvironment.RemoteDll(assemblyFullName);
return currentFlowEnvironment.RemoteDll(assemblyName);
}
public async Task<bool> RemoveConnectInvokeAsync(string fromNodeGuid, string toNodeGuid, ConnectionInvokeType connectionType)

View File

@@ -87,16 +87,17 @@ namespace Serein.NodeFlow.Env
/// <summary>
/// 程序集封装依赖
/// </summary>
/// <param name="library"></param>
/// <param name="libraryInfo"></param>
/// <returns></returns>
public static Library.Library ToLibrary(this Library.NodeLibrary library)
public static Library.Library ToLibrary(this Library.NodeLibraryInfo libraryInfo)
{
var tmp = library.Assembly.ManifestModule.Name;
//var tmp = library.Assembly.ManifestModule.Name;
return new Library.Library
{
AssemblyName = library.Assembly.GetName().Name,
FileName = library.FileName,
FilePath = library.FilePath,
AssemblyName = libraryInfo.AssemblyName,
//AssemblyName = library.Assembly.GetName().Name,
FileName = libraryInfo.FileName,
FilePath = libraryInfo.FilePath,
};
}

View File

@@ -112,6 +112,11 @@ namespace Serein.NodeFlow.Env
return prjectInfo;
}
/// <summary>
/// 远程环境下加载项目
/// </summary>
/// <param name="flowEnvInfo"></param>
/// <param name="filePath"></param>
public void LoadProject(FlowEnvInfo flowEnvInfo, string filePath)
{
Console.WriteLine("加载远程环境");
@@ -120,13 +125,13 @@ namespace Serein.NodeFlow.Env
var libmds = flowEnvInfo.LibraryMds;
foreach (var lib in libmds)
{
NodeLibrary nodeLibrary = new NodeLibrary
NodeLibraryInfo nodeLibraryInfo = new NodeLibraryInfo
{
FullName = lib.LibraryName,
AssemblyName = lib.AssemblyName,
FilePath = "Remote",
};
var mdInfos = lib.Mds.ToList();
UIContextOperation?.Invoke(() => OnDllLoad?.Invoke(new LoadDllEventArgs(nodeLibrary, mdInfos))); // 通知UI创建dll面板显示
UIContextOperation?.Invoke(() => OnDllLoad?.Invoke(new LoadDllEventArgs(nodeLibraryInfo, mdInfos))); // 通知UI创建dll面板显示
foreach (var mdInfo in mdInfos)
{
MethodDetailss.TryAdd(mdInfo.MethodName, new MethodDetails(mdInfo)); // 从DLL读取时生成元数据
@@ -397,7 +402,7 @@ namespace Serein.NodeFlow.Env
Console.WriteLine("远程环境尚未实现的接口LoadDll");
}
public bool RemoteDll(string assemblyFullName)
public bool RemoteDll(string assemblyName)
{
// 尝试移除远程环境中的加载了的依赖
Console.WriteLine("远程环境尚未实现的接口RemoteDll");

View File

@@ -15,6 +15,8 @@ namespace Serein.NodeFlow.Tool
{
private Assembly _pluginAssembly;
public string FullName => _pluginAssembly.FullName;
/// <summary>
/// 加载程序集
/// </summary>
@@ -35,6 +37,12 @@ namespace Serein.NodeFlow.Tool
return null; // 保持默认加载行为
}
public List<Type> LoadFlowTypes()
{
return _pluginAssembly.GetTypes().ToList();
}
/// <summary>
/// 是否对程序集的引用
/// </summary>

View File

@@ -19,6 +19,7 @@ public static class NodeMethodDetailsHelper
return type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
.Where(m => m.GetCustomAttribute<NodeActionAttribute>()?.Scan == true);
}
/// <summary>
/// 创建方法信息
/// </summary>
@@ -250,22 +251,6 @@ public static class NodeMethodDetailsHelper
IsParams = hasParams, // 判断是否为可变参数
};
//string explicitTypeName = GetExplicitTypeName(explicitParemType);
//var items = GetExplicitItems(explicitParemType, explicitTypeName);
//if ("Bool".Equals(explicitTypeName)) explicitTypeName = "Select"; // 布尔值 转为 可选类型
//return new ParameterDetails
//{
// IsExplicitData = isExplicitData, //attribute is null ? parameterInfo.HasDefaultValue : true,
// Index = index, // 索引
// ExplicitTypeName = explicitTypeName, // Select/Bool/Value
// ExplicitType = explicitParemType,// 显示的入参类型
// Convertor = func, // 转换器
// DataType = dataType, // 实际的入参类型
// Name = parameterInfo.Name,
// DataValue = parameterInfo.HasDefaultValue ? parameterInfo?.DefaultValue?.ToString() : "", // 如果存在默认值,则使用默认值
// Items = items.ToArray(), // 如果是枚举值入参,则获取枚举类型的字面量
// IsParams = hasParams, // 判断是否为可变参数
//};
}

View File

@@ -316,10 +316,10 @@ namespace Serein.Workbench
/// </summary>
private void FlowEnvironment_DllLoadEvent(LoadDllEventArgs eventArgs)
{
NodeLibrary nodeLibrary = eventArgs.NodeLibrary;
NodeLibraryInfo nodeLibraryInfo = eventArgs.NodeLibraryInfo;
List<MethodDetailsInfo> methodDetailss = eventArgs.MethodDetailss;
var dllControl = new DllControl(nodeLibrary);
var dllControl = new DllControl(nodeLibraryInfo);
foreach (var methodDetailsInfo in methodDetailss)
{
@@ -341,7 +341,7 @@ namespace Serein.Workbench
var menu = new ContextMenu();
menu.Items.Add(CreateMenuItem("卸载", (s, e) =>
{
if (this.EnvDecorator.RemoteDll(nodeLibrary.FullName))
if (this.EnvDecorator.RemoteDll(nodeLibraryInfo.AssemblyName))
{
DllStackPanel.Children.Remove(dllControl);
}

View File

@@ -16,17 +16,17 @@ namespace Serein.Workbench.Node.View
/// </summary>
public partial class DllControl : UserControl
{
private readonly NodeLibrary nodeLibrary;
private readonly NodeLibraryInfo nodeLibraryInfo;
public DllControl()
{
Header = "DLL文件"; // 设置初始值
InitializeComponent();
}
public DllControl(NodeLibrary nodeLibrary)
public DllControl(NodeLibraryInfo nodeLibraryInfo)
{
this.nodeLibrary = nodeLibrary;
Header = "DLL name : " + nodeLibrary.FullName;
this.nodeLibraryInfo = nodeLibraryInfo;
Header = "DLL name : " + nodeLibraryInfo.AssemblyName;
InitializeComponent();
}