Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/315.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用IDisposable时卸载AppDomain_C#_Dispose_Appdomain - Fatal编程技术网

C# 使用IDisposable时卸载AppDomain

C# 使用IDisposable时卸载AppDomain,c#,dispose,appdomain,C#,Dispose,Appdomain,我有一个包含工厂方法的可封送类。工厂方法可用于在测试AppDomain中实例化类。我试图了解是否可以使用using(…)dispose模式来使用该类 我主要关心的是测试AppDomain是否被卸载——以及何时卸载。我在类中添加了一个静态标志,该标志在调用实例方法时设置。如果appdomain没有卸载,那么我认为这个标志应该在后续调用中保留它的设置 示例类和测试控制台应用程序如下所示: using System; using System.Reflection; using System.Thre

我有一个包含工厂方法的可封送类。工厂方法可用于在测试AppDomain中实例化类。我试图了解是否可以使用using(…)dispose模式来使用该类

我主要关心的是测试AppDomain是否被卸载——以及何时卸载。我在类中添加了一个静态标志,该标志在调用实例方法时设置。如果appdomain没有卸载,那么我认为这个标志应该在后续调用中保留它的设置

示例类和测试控制台应用程序如下所示:

using System;
using System.Reflection;
using System.Threading;

namespace AppDomainInDispose
{
    public class TestClass : MarshalByRefObject, IDisposable
    {
        public void Run()
        {
            Console.WriteLine("Hello from {0}", Thread.GetDomain().FriendlyName);
            if (_flag)
                Console.WriteLine("Flagged!");
            else
                _flag = true;
        }

        private static bool _flag = false;

        public static TestClass InstantiateInTestDomain()
        {
            var callingDomain = Thread.GetDomain();
            var setup = new AppDomainSetup() { ApplicationBase = callingDomain.SetupInformation.ApplicationBase };
            _domain = AppDomain.CreateDomain("test-domain", null, setup);
            _domain.DomainUnload += _domain_DomainUnload;

            var assembly = Assembly.GetAssembly(typeof(TestClass)).CodeBase;
            var proxy = _domain.CreateInstanceFromAndUnwrap(assembly, "AppDomainInDispose.TestClass") as TestClass;

            return proxy;
        }

        static void _domain_DomainUnload(object sender, EventArgs e)
        {
            Console.WriteLine("Unloading");
        }

        public static AppDomain _domain = null;

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        ~TestClass()
        {
            Dispose(false);
        }

        private void Dispose(bool disposing)
        {
            if(disposing)
            {
                //AppDomain.Unload(_domain);    // can't, as I'm in the AppDomain
            }
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            using(var testClass = TestClass.InstantiateInTestDomain())
            {
                testClass.Run();
            }
            using (var testClass = TestClass.InstantiateInTestDomain())
            {
                testClass.Run();    // if the appdomain hasn't been unloaded then the static flag will still be set
            }

            Console.ReadKey();
        }
    }
}
在这个有限的测试中,似乎正在卸载AppDomain——但我不确定在哪里。有人能解释一下AppDomain的情况吗?这是一个非常糟糕的想法吗


编辑:看起来你可以有多个AppDomain共享同一个名称,我没有意识到这一点。此外,DomainUnload事件没有被触发,因此我可能会假设该域没有被卸载。或者在某些情况下(可能在宿主进程关闭时)不会触发事件。

Hmmm。。事情变得有点复杂了。如果您想确保在使用块结束后卸载应用程序域,下面是一个这样的实现。我在这里分离了两个关注点:“创建应用程序域和处理应用程序域”和“正在应用程序域中加载的类型本身”。(所有这些都在主程序类中)

公共类GenericDisposable:IDisposable
{
公共操作Dispose{get;set;}
公共T对象{get;set;}
void IDisposable.Dispose()无效
{
处置();
}
}
公共静态GenericCreateDomainWithType()的一次性使用
{
var appDomain=appDomain.CreateDomain(“测试域”);
var inst=appDomain.CreateInstanceAndUnwrap(typeof(T).Assembly.FullName,typeof(T).FullName);
appDomain.DomainUnload+=(a,b)=>Console.WriteLine(“已卸载”);
返回新的GenericDisposable(){Dispose=()=>AppDomain.Unload(AppDomain),Object=(T)inst};
}
公共类用户:MarshalByRefObject
{
公共空间
{
Console.WriteLine(“来自用户的你好”);
}
}
//用法
静态void Main()
{
使用(var wrap=CreateDomainWithType())
{
wrap.Object.Sayhello();
}
Console.Read();
}
亡灵巫术。

一次性操作对我不起作用,因为操作委托不可序列化。
我是这样做的:

Protected Overridable Sub Dispose(disposing As Boolean)
    If Not disposedValue Then
        If disposing Then
            ' TODO: verwalteten Zustand (verwaltete Objekte) entsorgen.

            If Me.LoadContext IsNot Nothing Then
                Me.LoadContext.Unload()
                Me.LoadContext = Nothing
            End If

            If Me.Stream IsNot Nothing Then
                Me.Stream.Dispose()
                Me.Stream = Nothing
            End If

            'If Parameters.m_parameterValues IsNot Nothing Then
            '    Parameters.m_parameterValues.Clear()
            '    Parameters.m_parameterValues = Nothing
            'End If

            If Me.Domain IsNot Nothing Then
                ' https://stackoverflow.com/questions/7793074/unload-an-appdomain-while-using-idisposable
                Dim thread As System.Threading.Thread = New System.Threading.Thread(
                  Sub(domain As System.AppDomain)
                      Try
                          ' System.Threading.Thread.Sleep(1000)
                          System.AppDomain.Unload(domain)
                      Catch ex As System.Threading.ThreadAbortException
                          ' System.Console.WriteLine(ex.Message)
                          System.GC.Collect()
                          System.GC.WaitForPendingFinalizers()
                      End Try
                  End Sub
                )
                thread.IsBackground = True
                thread.Start(Me.Domain)
                Me.Domain = Nothing
            End If

            System.GC.Collect()
            System.GC.WaitForPendingFinalizers()
        End If

        ' TODO: nicht verwaltete Ressourcen (nicht verwaltete Objekte) freigeben und Finalize() weiter unten überschreiben.
        ' TODO: grosse Felder auf Null setzen.
    End If
    disposedValue = True
End Sub
秘密是在一个新的线程中进行:

Dim thread As System.Threading.Thread = New System.Threading.Thread(
      Sub(domain As System.AppDomain)
          Try
              System.AppDomain.Unload(domain)
          Catch ex As System.Threading.ThreadAbortException
              ' System.Console.WriteLine(ex.Message)
              System.GC.Collect()
              System.GC.WaitForPendingFinalizers()
          End Try
      End Sub
)
thread.IsBackground = True
thread.Start(Me.Domain)

然后线程被终止,但代码继续运行

所以——不要返回代理,而是返回一个围绕代理的包装器,它可以为您处理域。明白了:)Ta。“操作委托不可序列化”--如何使用
MarshalByRefObject
及其方法,该方法在加载到两个AppDomain的程序集中定义?
Dim thread As System.Threading.Thread = New System.Threading.Thread(
      Sub(domain As System.AppDomain)
          Try
              System.AppDomain.Unload(domain)
          Catch ex As System.Threading.ThreadAbortException
              ' System.Console.WriteLine(ex.Message)
              System.GC.Collect()
              System.GC.WaitForPendingFinalizers()
          End Try
      End Sub
)
thread.IsBackground = True
thread.Start(Me.Domain)