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

发布于 2024-09-18 20:50:35 字数 1971 浏览 5 评论 0原文

我已经看到了一些可能对我有帮助的例子,但我没有太多时间去探索它们,因为我今天才发现我的老板必须比计划提前一周演示这个,我想添加这个新功能。我会尽力保持这个简短而甜蜜。

好吧,这已经是我第十次试图纠正这个问题了,希望是这样。这是一个应用程序。数据行需要显示在 DataGridView 中(完成)。根据报告(完成),某些行会以不同方式突出显示。大多数报告都有自己的 SQL 文件,并在运行时从 INI 文件实现(完成)。然而,有些报告需要调用函数。该应用程序使用 SQLite 数据库。我想要 DLL 是报告,全部具有相同的格式,并且它们都返回 ReportRecord 列表。 ReportRecord 是在我的主应用程序中定义的一个类,但我也会在创建每个 DLL 时在它们中定义它。我想实例化 DLL,调用它的“GetRecords”函数,并在我的主应用程序中使用它。这是一些伪代码。如果你们能告诉我是否可能,或者给我一个更好的方法来做到这一点,我将不胜感激。

PSUEDOCODE

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

有办法做到这一点吗?

目前我有以下几点补充,直到找到为止:

        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();
        }

谢谢大家。

编辑:抱歉,伙计们,老实说,看到这些东西让我觉得自己很愚蠢。就像,我的大脑一片空白,无法集中注意力。 :) 你们提供的可能是最好的方法,但由于我必须在周二之前准备好一个高质量的演示,并且在那之前不应该有更多的报告添加需要的功能,我将保持这个开放。一旦我的老板出城演示它,我将致力于实施它。但现在,除非我看到一个非常非常(对于两岁的孩子)直接的例子,否则这个问题将得不到答案。

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). 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). However, some reports need to call a Function. The application is using an SQLite database. I would like to have DLLs that are reports, all of the same format, and all of them return a List of ReportRecord. ReportRecord is a class defined in my main application but I would also define it in each DLL when they are created. I want to instantiate the DLL, call it's "GetRecords" function, and use it in my main application. 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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

缺⑴份安定 2024-09-25 20:50:35

您可以简单地创建一个实现以下接口的 C# 库项目,并将二进制文件存储在数据库或文件系统中。然后,您可以从原始程序集字节/文件路径加载程序集并实例化对象。通过反射,您还可以直接调用构造函数,但我更喜欢使用工厂模式来完成此类任务。

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");
}

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. 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");
}
简单气质女生网名 2024-09-25 20:50:35

不要从 DLL 的角度来看待它,它们是原始文件,而是从程序集的角度来看待,这就是 .NET 看待事物的方式。您可以使用Assembly.Load加载程序集。话虽如此,您是否考虑过更通用的解决方案,例如控制反转

Don't look at this in terms of DLL's, which are the raw files, but Assemblies, which is how .NET sees things. You can load an Assembly using Assembly.Load. Having said this, have you considered a more generic solution, such as inversion of control?

一指流沙 2024-09-25 20:50:35

我不太明白你到底想做什么,国际奥委会可能是解决这个问题的方法。但据我了解,您可以通过纯粹的反思来做到这一点。

请注意,这远不是做这样的事情的理想方式,但你要求它:)

就这样了(在我的头顶,所以如果有什么问题不要开枪打我,它应该非常接近) ,尽管并非万无一失)

// 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);

I'm not really understanding what exactly you're trying to do, and IOC is probably the way to go here. 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);
提笔落墨 2024-09-25 20:50:35

考虑使用插件架构,例如用于管理报告模块的托管可扩展性框架

Consider a plugin architecture, such as the Managed Extensibility Framework, for managing your report modules.

梦年海沫深 2024-09-25 20:50:35

为此,您可能需要考虑使用托管扩展性框架。它使这种类型的操作变得微不足道。

您可以在上面下载 .NET 3.5 的它(它已经在 .NET 4 的框架中)。通过使用 MEF,您可以通过 DirectoryCatalog 一次导入所有导出的“报告”的集合,并且它将为您处理所有连接。

有关详细信息,请参阅在此处导入集合的帮助。

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). 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.

For details, see the help on Importing Collections here.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文