简体   繁体   English

C#:如何动态加载/实例化DLL?

[英]C#: How do I dynamically load/instantiate a DLL?

I've seen a couple examples out there that could possibly help me, but I don't have that much time to explore them as I just found out today that my bosses have to demo this a week earlier than planned, and I want to add this new functionality. 我已经看到了一些可能对我有帮助的示例,但是我没有太多的时间去探索它们,因为我今天发现我的老板们必须比原计划提前一周进行演示,我想添加此新功能。 I'll try and keep this short and sweet. 我会尽量保持简短和甜美。

Ok, this is like my 10th time trying to right this to make it clear, hopefully it is. 好的,这就像我第十次尝试纠正此问题以使其更清晰,希望是的。 This is an application. 这是一个应用程序。 Rows of data need to be displayed in a DataGridView (done). 数据行需要在DataGridView中显示(完成)。 Some rows are highlighted differently based on reports (done). 根据报告(完成),某些行以不同的方式突出显示。 Most reports have their own SQL file and are implemented at runtime from an INI file (done). 大多数报告都有自己的SQL文件,并在运行时从INI文件实现(完成)。 However, some reports need to call a Function. 但是,某些报告需要调用功能。 The application is using an SQLite database. 该应用程序正在使用SQLite数据库。 I would like to have DLLs that are reports, all of the same format, and all of them return a List of ReportRecord. 我想拥有作为报告的DLL,它们都具有相同的格式,并且它们都返回ReportRecord的列表。 ReportRecord is a class defined in my main application but I would also define it in each DLL when they are created. ReportRecord是在我的主应用程序中定义的类,但是在创建每个DLL时,我也会在每个DLL中定义它。 I want to instantiate the DLL, call it's "GetRecords" function, and use it in my main application. 我想实例化DLL,将其称为“ GetRecords”函数,然后在我的主应用程序中使用它。 Here is some psuedocode. 这是一些伪代码。 If you guys can tell me if it's possible, or give me an idea of a better way to do this, I'd appreciate it. 如果你们可以告诉我是否可行,或者给我一个更好的方法的想法,我将不胜感激。

PSUEDOCODE 伪码

 foreach (string str in System.IO.Directory.GetFiles("C:\\ReportDlls", "*.dll"))
 {
   //Instantiate DLL e.g. newReport
   //_lstReportRecords.AddRange(newReport.GetReportRecords());
 }    

Is there anyway to do this? 反正有这样做吗?

Currently, I have the following to supplement until I find this out: 目前,在找到答案之前,我需要补充以下内容:

        private void RefreshReports(string strReportTitle)
        {
            _lstReportRecords = _lstReportRecords.Where(rr => rr.Description != strReportTitle).ToList<ReportRecord>();
            string strColumn = iniFile.GetString(strReportTitle, "Column", "");


            if (strColumn != null)
            {
                _lstReportRecords.AddRange(_dataController.BuildReportList(strColumn, strReportTitle, GetReportSQL(strReportTitle)));
            }
            else
            {
                switch (strReportTitle)
                {
                    case "Improper Indenture":
                        _lstReportRecords.AddRange(_dataController.ImproperIndenture());
                        break;
                    case "Skipping Figure":
                        _lstReportRecords.AddRange(_dataController.SkippingFigure());
                        break;
                    default: break;
                }
            }
            FormatCells();
        }

Thanks everyone. 感谢大家。

Edit : Sorry guys, looking at that stuff is honestly making me feel stupid. 编辑 :对不起,老兄,看着这些东西真让我感到愚蠢。 Like, my mind is going blank and all and can't concentrate on it. 就像,我的脑子一片空白,全神贯注。 :) What you guys have provided is probably the best way, but since I have to have a quality Demo ready by Tuesday and there shouldn't be any more reports added needing functions until then, I'm going to keep this open. :)你们提供的可能是最好的方法,但是由于我必须在星期二之前准备好质量的演示,并且在那之前不应再添加任何需要功能的报告,因此我将保持这种状态。 Once my boss is out of town to demo it, I'll work on implementing this. 我的老板出门演示后,我将继续实施。 But right now, it's going to go unanswered unless I see an example that is very very (for 2 year olds) straight forward. 但是现在,除非我看到一个非常非常(针对2岁儿童)的例子,否则它将无法解决。

You can simply create a C# library project implementing the interfaces below and store the binary file in the database or on the file system. 您可以简单地创建一个实现以下接口的C#库项目,然后将二进制文件存储在数据库或文件系统中。 You could then load the assembly from raw assembly bytes/file path an instantiate an object. 然后,您可以从原始程序集字节/文件路径加载程序集,以实例化对象。 With reflection you can also call the constructor directly, but i prefer the factory pattern for such tasks. 通过反射,您还可以直接调用构造函数,但是我更喜欢将工厂模式用于此类任务。

public interface IReportModule
{
}

public interface IReportModuleFactory
{
    IReportModule Create();
}

private static IReportModule CreateReportModuleFromRawAssemby(byte[] rawAssembly)
{
    var reportModule = Assembly.Load(rawAssembly);
    var factoryType = reportModule.GetExportedTypes()
        .FirstOrDefault(x => x.IsAssignableFrom(typeof(IReportModuleFactory)));
    if (factoryType != null)
    {
        var reportModuleFactory = (IReportModuleFactory)
            reportModule.CreateInstance(factoryType.FullName);
        return reportModuleFactory.Create();
    }
    else
        throw new NotImplementedException("rawAssembly does not implement IReportModuleFactory");
}

Don't look at this in terms of DLL's, which are the raw files, but Assemblies, which is how .NET sees things. 不要以DLL(原始文件)的角度来看问题,而要用Assemblies(.NET看到事物的样子)的观点来看。 You can load an Assembly using Assembly.Load . 您可以使用Assembly.Load加载程序Assembly.Load Having said this, have you considered a more generic solution, such as inversion of control ? 话虽如此,您是否考虑过更通用的解决方案,例如控制反转

I'm not really understanding what exactly you're trying to do, and IOC is probably the way to go here. 我不太了解您到底想做什么,IOC可能是您的选择。 But from what I understand, you could do this with pure reflection. 但是据我了解,您可以通过纯粹的反思做到这一点。

Mind you, this is far from the ideal way of doing things like this, but you're asking for it :) 提醒您,这远非理想的方法,但您正在要求它:)

Here it goes (top of my head, so don't shoot me if anything is wrong, it should be pretty close, though not foolproof) 它就到了(我的头顶,所以如果有任何问题请不要向我开枪,它应该很近,尽管不是万无一失的)

// load assembly
var assemblyWithReport = Assembly.LoadFrom("Path of your assembly"); 

// or another Loadxx to get the assembly you'd 
// like, whether it's referenced or not

// load type
var reportType = assemblyWithReport.GetTypes().ToList()
   .Where(t => t.Name == "ReportRecord").Single();

// create instance of type
var instance = Activator.CreateInstanceOf(reportType);

// get getrecords method of the type
var getRecordsMethod = reportType.GetMethod("GetRecords");

// invoke getrecords method on the instance
object result = getRecordsMethod.Invoke(instance, null);

考虑一个用于管理报表模块的插件体系结构,例如Managed Extensibility Framework

You may want to consider using the Managed Extensibility Framework for this. 您可能要考虑使用托管扩展框架 It makes this type of operation trivial. 它使这种类型的操作变得微不足道。

You can download it above for .NET 3.5 (it's in the framework in .NET 4 already). 您可以在上方下载.NET 3.5的版本(它已经在.NET 4的框架中)。 By using MEF, you could just import the collection of all exported "reports" in one shot via a DirectoryCatalog, and it will take care of all of the wiring for you. 通过使用MEF,您可以通过DirectoryCatalog一次导入所有导出的“报告”的集合,它将为您处理所有连接。

For details, see the help on Importing Collections here . 有关详细信息,请参阅此处的有关导入集合的帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM