1

我有一个创建 DLL 的解决方案和另一个使用它们的解决方案。它是一个工具箱,可以将各种工具作为插件加载。起初一切顺利:

这是两个类,都在单独的 cs 文件中:

namespace PIClasses
{
    public class PI_base : UserControl
    {
        public PI_base()  { }

        public string Description { get; set; }
        public string Version { get; set; }

        private void InitializeComponent()
        {
            this.SuspendLayout();
            this.Name = "PI_base";
             this.ResumeLayout(false);
        }
    }
}


namespace PIClasses
{
    public class PIC_Clock : PI_base
    {
        private System.ComponentModel.IContainer components = null;
+       protected override void Dispose(bool disposing)
+       private void InitializeComponent()

        public System.Windows.Forms.Label st_time;
        public System.Windows.Forms.Timer clockTimer;

        public PIC_Clock()       {  InitializeComponent();  }

        private void clockTimer_Tick(object sender, EventArgs e)
        { st_time.Text = DateTime.Now.ToString("HH:mm:ss");   }

        private void PIC_Clock_Load(object sender, EventArgs e)
        {       clockTimer.Enabled = true;   }

    }
}

这就是工具箱如何在列表框的 selectionchanged 事件中创建一个实例,其中包含找到的 DLL。它被创建得很好,时钟滴答作响..:

  string DLLname = lb_tools.SelectedItem.ToString();    // pick one from a list of DLLs
  Assembly assembly = Assembly.LoadFrom(DLLname);       //load the assembly

  foreach (Type type in assembly.GetExportedTypes())    // look for the tool class
  {
     if (type.Name != "PI_base")                        // skip the base class
     {
         var c =  Activator.CreateInstance(type);
         tp_test2.Controls.Add((Control)c);            // I can add is to a tabpage as Control
         ((Control)c).Dock = DockStyle.Fill;           // this works, too

         //PI_base ctl = (PI_base)c;                   // <--this cast gets a runtime error
         //PI_base ctl = c; // as   PI_base ;          // this cast get null
         //st_status.Text = ctl.Description;           // example of what the base class might deliver

    break;                                        // done when we find the real thing
     }

但是转换为 PI_base 类会在运行时创建一个无效的转换异常。它说

'“PIClasses.PIC_Clock”类型的对象不能转换为“PIClasses.PI_base”类型。'

好的,但是为什么以及如何正确地做到这一点。我很烦。或者盲人。或者有点笨。或以上任何一种;-)


编辑:

好的,伙计们,这是有道理的——感谢斯科特如此明确地拼写出来。

我接受了您的第二个建议,并为基类创建了一个专用的 PluginCore 项目。

我仍然遇到了一个问题..:我已经将 PluginCore 设为类库 (PI_Base) 并从中生成了一个 DLL (PI_Base.DLL)。

我已经从 ClockPlugin 项目中清除了对原始基类的所有引用,并添加了对 PI_Base.DLL 的引用。我还在 PI_Base 命名空间中添加了 using 子句。我已经从 csproj 目标中删除了原始基类引用。新创建的对基本 DLL 的引用对我来说看起来不错。(?)

但是我在构建时收到“找不到类型或命名空间”错误。这很奇怪,因为我可以右键单击基类类型并说“转到定义”,它会显示它在元数据中找到的东西!但是在构建 ClockPlugin DLL 时,它说既没有找到命名空间 (PI_Base) 也没有找到基本类型 (PI_ToolBase)。

我想我错过了一些小但必不可少的东西..

以下是 csproj 文件的相关部分:

<ItemGroup>
    <Reference Include="PI_Base, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
      <SpecificVersion>False</SpecificVersion>
      <HintPath>..\..\PI_Base\PI_Base\bin\Debug\PI_Base.dll</HintPath>
    </Reference>
    <Reference Include="System" />
..
..
    <Compile Include="PIC_Clock.cs">
      <SubType>UserControl</SubType>
    </Compile>
..
..
  <Target Name="BuildPlugins">
    <CSC Sources="PIC_Clock.cs" TargetType="library" 
    OutputAssembly="$(OutputPath)PIC_Clock.dll" 
    EmitDebugInformation="true" />
  </Target>
  <Target Name="AfterBuild" DependsOnTargets="BuildPlugins">
  </Target>
  <PropertyGroup>
    <PostBuildEvent>call x_copy.bat
</PostBuildEvent>

这是构建失败的 PIC_Clock.cs 部分:

using PI_Base;


namespace PIClasses
{
    public class PIC_Clock : PI_ToolBase

编辑 2

事实上,CSC 命令缺少一些重要的东西。它的编译器调用与内部 Studio Build 完全不同,需要告知要包含哪些类以及要引用哪些类。如果我想与另一个程序共享它,我必须引用基类 DLL,例如:

<CSC Sources="PIC_Clock.cs" References="d:\p\c#13\toolbox\pi_base\pi_base\bin\debug\pi_base.dll" TargetType="library" OutputAssembly="$(OutputPath)PIC_Clock.dll" EmitDebugInformation="true" />
4

1 回答 1

2

所有插件都需要共享一个基类。如果您在每个插件中都有一个副本,PI_base.cs它将无法工作,因为即使它们具有相同的名称和命名空间以及完全相同的布局,它们仍然不被视为“同一类”。

我认为这就是您的程序目前的样子

MainProject
 |-- PI_base.cs
 L-- Main.cs

ClockPlugin
 |-- PI_base.cs
 L-- PIC_Clock.cs

相反,您需要进行两种设置之一

MainProject
 |-- PI_base.cs
 L-- Main.cs

ClockPlugin
 |-REFRENCES
 |  L-- MainProject
 L-- PIC_Clock.cs

以便您的插件PI_Base在主项目中引用(当您更改 的程序集版本号时,此方法容易受到插件破坏MainProject),或者

MainProject
 |-REFRENCES
 |  L-- PluginCore
 L-- Main.cs

PluginCore
 |-- PI_base.cs

ClockPlugin
 |-REFRENCES
 |  L-- PluginCore
 L-- PIC_Clock.cs

所以现在你的 EXE 和你的插件 DLL 都读取一个PluginCore.dll,这会导致你的项目中有更多的 DLL,但是你可以在MainProject不破坏插件的情况下更改程序集版本号。

于 2014-03-05T20:15:26.827 回答