首页 > 解决方案 > 将属于动态加载的 dll 的类强制转换为属于另一个 dll 的抽象类

问题描述

我在从外部程序集中使用抽象类强制转换 ViewModel 类时遇到问题。

我有 2 个 dll 和一个可执行文件:

一个抽象类到dll Cockpit.RUN.Common.dll中,这个Dll被引用:在dll Cockpit.RUN.ViewModels的另一个项目和可执行Cockpit.RUN.Test的项目中,但是没有引用Cocpit.RUN.ViewModels在可执行的项目中,因为它是动态加载的

抽象类:(dll)

using Caliburn.Micro;

namespace Cockpit.RUN.Common
{
    public abstract class PluginModel : PropertyChangedBase
    {
        public abstract double Width { get; set; }
        public abstract double Height { get; set; }
        public abstract double Left { get; set; }
        public abstract double Top { get; set; }

        private double zoomfactorfrompluginmodel;
        public double ZoomFactorFromPluginModel
        {
            get => zoomfactorfrompluginmodel;
            set
            {
                zoomfactorfrompluginmodel = value;
                NotifyOfPropertyChange(() => ZoomFactorFromPluginModel);
            }
        }
        public string NameUC;
    }
}

第二个包含 viewmodels Cockpit.RUN.ViewModels.dll 的 dll 我在这个 dll 中有很多不同的插件:Push_ViewModel、Switch_ViewModel....

我用抽象类派生每个类,例如 Push_ViewModel:

using Cockpit.RUN.Common;
using System.Windows;
using System.Windows.Input;

namespace Cockpit.RUN.ViewModels
{
    public class PushButton_ViewModel : PluginModel
    {

        public PushButton_ViewModel(params object[] settings)
        {
            NameUC = (string)settings[2];
            Layout = new LayoutPropertyViewModel();
        }

        public override double Left
        {
            get => Layout.UCLeft;
            set => Layout.UCLeft = value;
        }
        public override double Top
        {
            get => Layout.UCTop;
            set => Layout.UCTop = value;
        }
        public override double Width
        {
            get => Layout.Width;
            set => Layout.Width = value;
        }
        public override double Height
        {
            get => Layout.Height;
            set => Layout.Height = value;
        }                         
    }
}

再说一件事,这个插件 dll 在引导程序期间动态加载

    protected override IEnumerable<Assembly> SelectAssemblies()   
    {                                                                                                                                  
        var assemblies = new List<Assembly>();
        assemblies.AddRange(base.SelectAssemblies());
        assemblies.Add(Assembly.LoadFile(@"J:\ProjetC#\Cockpit-master\Cockpit.RUN.Test\bin\Debug\Cockpit.RUN.ViewModels.dll")); 
        assemblies.Add(Assembly.LoadFile(@"J:\ProjetC#\Cockpit-master\Cockpit.RUN.Test\bin\Debug\Cockpit.RUN.Views.dll")); 
        return assemblies;   
    }  

所以问题是当我想用抽象基础 PulginModel 转换每个 ViewModel 时,我的结果为空:

        using Cockpit.RUN.Common;
                    :
                    :
        public BindableCollection<PluginModel> MyCockpitPlugins { get; set; }

                    :
                    :

        model = "Cockpit.RUN.ViewModels.PushButton_ViewModel, Cockpit.RUN.ViewModels";
        var typeClass = Type.GetType(model); // its ok 
        var viewmodel = resolutionRoot.TryGet(typeClass, param); // Its ok i have an instance of PushButton_ViewModel

        var v = viewmodel as PluginModel; //-> not ok its null
        var w = (PluginModel)viewmodel; //-> not ok its error

        // So i cant display my  list of views associated 
        MyCockpitPlugins.Add(v);

我做错了什么吗?

在强制转换之前在中断调试时加载的程序集:

过程的丝网印刷

以及 typeof 和 GetType 的结果:

typeof(PluginModel) gives {Name = "PluginModel" FullName = "Cockpit.RUN.Common.PluginModel"}

viewmodel.GetType().BaseType gives {Name = "PluginModel" FullName = "Cockpit.RUN.ViewModels.PluginModel"}

标签: c#ninjectcaliburn.micro

解决方案


接口(dll):

public interface IPlugin
{
    ICallbacks Callbacks { get; set; }

    string NameUC { get; set; }

    double Width { get; set; }
    double Height { get; set; }
    double Left { get; set; }
    double Top { get; set; }

    double ZoomFactorFromPluginModel { get; set; }
}
public interface ICallbacks
{
    void SomeCallback();
}

您的实施:

public class PushButton_ViewModel : PluginModel, IPlugin
{
    // How was this going to work? Who makes the instance?
    //public PushButton_ViewModel(params object[] settings)
    //{
    //    NameUC = (string)settings[2];
    //    Layout = new LayoutPropertyViewModel();
    //}

    public ICallbacks Callbacks { get; set; }

    public override double Left
    {
        get => Layout.UCLeft;
        set => Layout.UCLeft = value;
    }
    public override double Top
    {
        get => Layout.UCTop;
        set => Layout.UCTop = value;
    }
    public override double Width
    {
        get => Layout.Width;
        set => Layout.Width = value;
    }
    public override double Height
    {
        get => Layout.Height;
        set => Layout.Height = value;
    }                         
}

然后初始化它

 Type t = Type.GetType("PushButton_ViewModel");
 object obj = FormatterServices.GetUninitializedObject(t);
 IPlugin instance = obj as IPlugin;
 instance.NameUC = "the name";
 instance.Callbacks = new CallbacksModel();

推荐阅读