У меня есть решение, которое создает библиотеки 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; }
}
}
и вот как Toolbox создает экземпляр в событии 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. Я также добавил предложение using в пространство имен PI_Base. И я удалил исходную ссылку на базовый класс из цели csproj. Недавно созданная ссылка на базовую DLL выглядит нормально. (?)
Но я получаю сообщение об ошибке «Тип или пространство имен не найдено» при сборке. Что странно, так как я могу щелкнуть правой кнопкой мыши тип базового класса и сказать «перейти к определению», и он выводит то, что находит в метаданных! Но при создании DLL ClockPlugin он говорит, что ни пространство имен (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, и ему нужно указать, какие классы включать, а также на какие ссылаться. Я должен сослаться на 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" />
PI_base
находится в одной сборке, и что все остальные классы (производные от него) используют эту сборку. - person Peter Ritchie   schedule 05.03.2014