如何仅在引用的DLL存在时在C#中创建表单

如何仅在引用的DLL存在时在C#中创建表单,c#,winforms,dll,C#,Winforms,Dll,我开发了一个Winforms C#应用程序,其中有一个表单需要引用dll才能工作。所有其他申请表(包括主申请表)都不需要它。我希望能够在程序启动时检查引用的DLL是否存在,并仅在该DLL为真时创建/加载该特定表单。我怎么能这么做?在当前状态下,如果dll不存在,则我的应用程序在启动时崩溃。 感谢与本机导入不同,C#动态加载所有依赖程序集。在执行任何用户代码之前,依赖性故障仍然可能使程序崩溃,但这种情况非常罕见 为了调用Main函数(通常在Program.cs中),运行时必须解析类成员使用的所有类

我开发了一个Winforms C#应用程序,其中有一个表单需要引用dll才能工作。所有其他申请表(包括主申请表)都不需要它。我希望能够在程序启动时检查引用的DLL是否存在,并仅在该DLL为真时创建/加载该特定表单。我怎么能这么做?在当前状态下,如果dll不存在,则我的应用程序在启动时崩溃。 感谢

与本机导入不同,C#动态加载所有依赖程序集。在执行任何用户代码之前,依赖性故障仍然可能使程序崩溃,但这种情况非常罕见

为了调用
Main
函数(通常在Program.cs中),运行时必须解析类成员使用的所有类型,以及
Main(string[]args)
本身使用的类型。从
Main
调用的函数(例如表单构造函数)使用的类型在
Main
开始执行并到达该函数之前不会被加载

几乎在所有情况下,与加载DLL相关的异常都将显示为
TypeLoadException
上的
InnerException
属性。当发生
TypeLoadException
时,中断调试器,并检查调用堆栈。这将让您知道在何处添加尝试/捕获。。。如果它真的发生在“启动时”,它应该告诉您需要避免在
Program.cs
内部使用什么类(或者在
Main
所在的任何地方,如果您移动了它)

可以捕获
TypeLoadException
,如果这样做,就不可能使用编译失败的函数,但仍然可以使用其他类,甚至可以使用与无法编译的函数相同的类中的其他方法。对于显式加载或程序集,您不必玩任何把戏

下面是一个用法说明,它会导致整个类无法加载(
EarlyDependency
),或者允许整个类可用,除了
MethodA
LateDependency
):

A类:早期依赖性,i可比较
{
早期依赖场;
属性EarlyDependence属性a{get;set;}
int initialized=new earlydependence().Calculate();
int initializedB=LateDependency.LiteralConstant;
静态A类
{
早期依赖局部构造函数;
}
公共甲级()
{
早期依赖性局部中断;
如果(新随机().NextDouble()<.000001){
试一试{
//您无法捕获无法编译的函数内部
//因为函数中的代码永远无法运行
UsedByConstructor();
}
catch(TypeLoadException)
{
}
}
}
public earlydependence MethodWithReturnType();
public static earlydependence StaticMethodWithReturnType();
public void MethodWithParameter(earlydependence参数);
公共空间使用IT()
{
非特殊方法;
}
公共安全
{
试一试{
//您无法捕获无法编译的函数内部
//因为函数中的代码永远无法运行
使用它();
}
catch(TypeLoadException)
{
}
}
公共静态void UseItSomeMore()
{
迟发依赖局部统计方法;
}
专用void UsedByConstructor()
{
LateDependencyLocationMethodNamedConstructor;
}
}

您可以检查文件是否存在,如果存在,则创建/加载表单

if(File.Exists("myLibrary.dll")
{
   MyForm frm = new MyForm();
   frm.ShowDialog();
}

当然,您必须确保查找的路径正确。

您需要确保引用的DLL存在,然后动态加载包含要显示的表单的单独程序集。如果您尝试正常加载程序集,那么您的应用程序将以您描述的方式崩溃

试着这样做:

if (File.Exists("Referenced.dll")
{
    var assembly = Assembly.LoadFile("AssemblyContainingFormThatReferencesReferenced.dll");
    var type = assembly.GetType("TheForm");
    var form = Activator.CreateInstance(type) as Form;
    form.ShowDialog();
}

调查另请参见:可能的重复将不起作用。
MyForm
需要引用
myLibrary.dll
才能加载其程序集。您必须使用反射来实例化表单,才能使其工作。@Enigmativity:您错了,JIT不会预编译整个程序集,只预编译所需的每个类型和所需的每个类。如果在另一个DLL中找到了某个类型的成员变量,或者该类型显示为方法签名(参数类型或返回类型),则编译过程将在实际使用该类型之前需要该类型,但是函数中的局部变量在函数被实际调用之前不会触发程序集加载。@BenVoigt-听起来我应该对该代码的所有变体进行完整测试,以确保它们工作或不工作。@Enigmativity that.
File.Exists
不会检查程序集可以找到的所有位置。如果发生异常,最好尝试加载并捕获异常(因为没有
TryXYZ
版本的
Assembly.Load
——如果有更好的版本)@BenVoigt-我认为这意味着OP正在检查特定位置是否存在特定DLL。我不知道OP的确切情况,但我想到了这样一个用例:程序生成数据,并有“导出到CSV”和“导出到Excel”按钮。当执行Excel导出时,应用程序将使用Excel.Workbook类创建文件,对于CSV导出,它是.NET中内置的file.WriteAllText函数。如果用户没有安装Office,那么当然Excel.Workbook类将不可用,但它不应阻止程序运行并具有“导出到CSV”选项。@BenVoigt-EBrown建议的插件体系结构是一种可行的方法。
if (File.Exists("Referenced.dll")
{
    var assembly = Assembly.LoadFile("AssemblyContainingFormThatReferencesReferenced.dll");
    var type = assembly.GetType("TheForm");
    var form = Activator.CreateInstance(type) as Form;
    form.ShowDialog();
}