C# Can';我找不到从windows服务中删除/重新启动内存中的DLL状态的方法

C# Can';我找不到从windows服务中删除/重新启动内存中的DLL状态的方法,c#,dll,.net-4.0,C#,Dll,.net 4.0,我使用的是第三方DLL,它在文件首次使用时读取文件,但从不检查其更改。我的想法是在AppDomain中加载DLL,并在第一次调用后卸载DLL——因此每次调用(或多或少)都会清除DLL的状态 这段代码每秒可以运行多次-效率低下,但这是我目前唯一使用此DLL的选项 问题是DLL的内存似乎甚至存在于我创建的其他AppDomain中——它仍然使用第一次读取文件时发现的相同值(并且它不再检查)。让DLL再次读取文件的唯一方法是重新启动服务 我是否不理解AppDomain,或者应该从不同的角度对此进行探讨

我使用的是第三方DLL,它在文件首次使用时读取文件,但从不检查其更改。我的想法是在AppDomain中加载DLL,并在第一次调用后卸载DLL——因此每次调用(或多或少)都会清除DLL的状态

这段代码每秒可以运行多次-效率低下,但这是我目前唯一使用此DLL的选项

问题是DLL的内存似乎甚至存在于我创建的其他AppDomain中——它仍然使用第一次读取文件时发现的相同值(并且它不再检查)。让DLL再次读取文件的唯一方法是重新启动服务

我是否不理解AppDomain,或者应该从不同的角度对此进行探讨


编辑:将DLL加载到我自己的域中的问题已通过MarshallByRefObject类解决(谢谢!),但我不希望它是跨域的。我想让这个DLL在这个AppDomain中生存和消亡-卸载方法是否足以粉碎这个DLL的状态出现在另一个AppDomain中的任何希望?

如果您在“//使用程序集”代码中直接使用DLL中的对象,那么您已经将DLL拉入当前AppDomain以及新的AppDomain。这意味着你还没有真正实现你的目标

您需要使用反射来使用加载到新AppDomain中的类和方法,而无需将dll拉入原始AppDomain。

此行:

Assembly lib = newDomain.Load(name);
由于
程序集
类被标记为
[Serializable]
,而不是
MarshalByRefObject
,因此会跨AppDomain边界对其进行序列化,导致程序集失败:

您可以创建自己的对象以将调用代理到另一个程序集中。有关更多信息,请参见MSDN中的示例。但基本思想是这样的:

public class Worker : MarshalByRefObject, IWorker
{
    public void DoWork() 
    { 
        // Load the assembly here. This code will run in the AppDomain
    }
}

public interface IWorker
{
    void DoWork();
}


public class Program
{
    public static void Main()
    {
        AppDomain ad = AppDomain.CreateDomain("New domain");

        // This line creates a proxy to your worker.
        IWorker remoteWorker = (IWorker) ad.CreateInstanceAndUnwrap(
            Assembly.GetExecutingAssembly().FullName,
            "Worker");

        remoteWorker.DoWork();

        ad.Unload();
    }
}
public class StartErUp : MarshalByRefObject {
    public void RunThatOtherDll() { ... }
}

您甚至可以更进一步,让您的工人类实现一个接口并将其放在共享程序集中。

不确定
//使用这里的assembly
部分中发生了什么,但我怀疑您所做的是无意中将程序集加载到调用的AppDomain中,例如,主应用程序的appDomain

您要做的是将使用该DLL的所有代码单独放入程序集中,理想情况下,在继承自MarshalByRefObject的类上使用一个非常简单的方法来启动它,如下所示:

public class Worker : MarshalByRefObject, IWorker
{
    public void DoWork() 
    { 
        // Load the assembly here. This code will run in the AppDomain
    }
}

public interface IWorker
{
    void DoWork();
}


public class Program
{
    public static void Main()
    {
        AppDomain ad = AppDomain.CreateDomain("New domain");

        // This line creates a proxy to your worker.
        IWorker remoteWorker = (IWorker) ad.CreateInstanceAndUnwrap(
            Assembly.GetExecutingAssembly().FullName,
            "Worker");

        remoteWorker.DoWork();

        ad.Unload();
    }
}
public class StartErUp : MarshalByRefObject {
    public void RunThatOtherDll() { ... }
}

然后使用AppDomain.CreateInstanceAndUnwrap()加载该类。类从MarshalByRefObject继承是很重要的,因为这会告诉CLR为它创建一个跨appdomain代理,而不是尝试跨AppDomains序列化(复制)它。

我不太明白为什么每次调用后都需要卸载DLL。有什么方法可以让你更清楚一点吗?你可以使用dotTrace或其他.net反编译器来查看哪个方法设置状态,然后通过反射调用它。+1获取加载信息;实例AppDomain.Load方法实际上与静态程序集.Load方法的行为相同,这有点误导。@Dan Bryant:实际上我的措辞可能有点误导:这一行导致程序集加载到两个AppDomain中。我更新了我的答案,希望能让它更清楚。@MarkByers:谢谢你的回答。然而,我发现我遇到了同样的问题。。。我应该调用AppDomain.Unload(ad)对吗?@Ryan,请注意,如果要卸载,“Worker”类不能在动态加载的程序集中;它需要位于一个单独的程序集中,以便原始程序集和动态加载的程序集引用。为此,通常使用接口(因此可以将实际MarshalByRefObject放入动态加载的程序集中)