在Unity中需要使用Disposing吗?

30

可能是Unity初学者的问题:在使用Unity时,您是否仍然需要在已注入对象上实现Dispose方法?或者甚至不需要这样做(因此由Unity自动完成)?这是在Web应用程序的上下文中。

3个回答

33

实现IDisposable与Unity无关。当您的类型使用非托管资源如文件时,应该实现该接口,因为这些资源不能被CLR垃圾回收。

Unity可以管理您的类型和实例的生命周期。对于这种情况,Unity提供了不同类型的LifeTimeManager来控制实例的生命周期。

只有当您使用ContainerControlledLifetimeManagerHierarchicalLifetimeManager注册实例时,Unity才会尊重IDisposable接口。这意味着,当您处理Unity-Container时,它也将在上述命名LifetimeManager注册的所有实现IDisposable接口的实例上调用Dispose

当您使用TransientLifetimeManager(每次调用容器上的Resolve时都会获得一个新实例)注册实现IDisposable接口的类型时,您需要自己调用Dispose方法。


1
由你决定。那么,我应该在什么时候调用它? - Mikhail Orlov
1
@MikhailOrlov 当您完成对对象的工作并且不再需要它时,调用Dispose方法。 - Jehof
3
不,问题在于何时对非单例对象调用Dispose?Unity不会自动执行此操作。最终我使用了具有明确作用域概念的Autofac。 - Mikhail Orlov
7
关于手动调用Dispose:如果您Resolve一个本身依赖于IDisposable对象的对象,那该怎么办?当您不再需要它时,您无法找到这些对象。此外,手动调用Dispose意味着您必须确保它已经注册为TransientLifetimeManager - 如果它在未来更改为不同的生命周期,您将处置共享/单例对象,这些对象可能正在被其他地方使用。 - Philip C

9

延伸Jehof所说的内容ContainerControlledLifetimeManagerHierarchicalLifetimeManager如果支持,都会调用类的.Dispose()方法。然而,有趣的是只有具体实现需要实现IDisposable接口,你正在映射的接口不需要。以下是一个简单的示例程序来说明。

using System;
using System.Threading;
using Microsoft.Practices.Unity;

namespace ConsoleApplication
{
    internal class Program
    {
        private interface IFoo
        {
        }

        private class Foo : IFoo, IDisposable
        {
            public Foo()
            {
                Console.WriteLine("Foo Created");
            }

            public void Dispose()
            {
                Console.WriteLine("Foo.Dispose() called");
            }
        }

        private class Bar
        {
            public Bar(IFoo foo)
            {
            }
        }

        private static void Main()
        {
            LifetimeManager manager;

            Console.WriteLine("Choose a lifetime manager to test:");
            Console.WriteLine(" 1: ContainerControlledLifetimeManager");
            Console.WriteLine(" 2: ExternallyControlledLifetimeManager");
            Console.WriteLine(" 3: HierarchicalLifetimeManager");
            Console.WriteLine(" 4: PerThreadLifetimeManager");
            Console.WriteLine(" 5: TransientLifetimeManager");

            int choice = int.Parse(Console.ReadLine());
            switch (choice)
            {
                case 1:
                    manager = new ContainerControlledLifetimeManager();
                    break;
                case 2:
                    manager = new ExternallyControlledLifetimeManager();
                    break;
                case 3:
                    manager = new HierarchicalLifetimeManager();
                    break;
                case 4:
                    manager = new PerThreadLifetimeManager();
                    break;
                case 5:
                    manager = new TransientLifetimeManager();
                    break;
                default:
                    return;
            }

            Console.WriteLine(manager.ToString());

            //Use a thread to test PerThreadLifetimeManager's Dispose actions.
            var thread = new Thread(() => PerformTest(manager));
            thread.Start();
            thread.Join();


            Console.WriteLine("Press enter to exit...");
            Console.ReadLine();
        }

        private static void PerformTest(LifetimeManager manager)
        {
            Console.WriteLine("Pre container creation");
            using (IUnityContainer container = new UnityContainer())
            {
                Console.WriteLine("Pre type regrestration");
                container.RegisterType<IFoo, Foo>(manager);

                Console.WriteLine("Pre bar1 resolve");
                var bar1 = container.Resolve<Bar>();

                Console.WriteLine("Pre bar2 resolve");
                var bar2 = container.Resolve<Bar>();

                Console.WriteLine("Leaving container scope.");
            }
        }
    }
}

1
我注意到你在PerformTest中使用'using'来控制容器。 如果你把它拿掉,那么你必须调用container.Dispose。 我认为Prism没有这样做,这就是为什么我没有看到我的服务被dispose的原因。 - imekon
@imekon Prism根据配置对Dispose函数调用有特殊规则。一些对象在不可见时立即被处理,而另一些对象则在导航离开后再次导航回来时被重用。 - Scott Chamberlain
我遇到的问题是我的服务dispose从未被调用。不幸的是,这会使硬件处于未定义状态,唯一的恢复方法是重新启动并重新上电硬件。当应用程序退出时,我通过执行Container.Dispose()来解决这个问题。 - imekon
@ScottChamberlain,你能帮我解决这个类似的问题吗?链接在这里:http://stackoverflow.com/questions/39954586/unitofwork-repository-database-connection-issue?noredirect=1#comment67199903_39954586 - Hiren Desai
1
已升级至Net Core 3.1,即时查看输出 https://dotnetfiddle.net/GKNw0y - Juan Pablo

0

在2018年1月11日,Unity新增了另一个生命周期管理器ContainerControlledTransientManager,它遵循IDisposable接口Add container 'owned' transient lifetime manager ContainerControlledTransientManager #37

因此,需要使用ContainerControlledTransientManager。这个生命周期管理器与TransientLifetimeManager相同,但如果对象实现了IDisposable接口,它将保持对该对象的强引用,并在容器被释放时进行处理。 如果创建的对象不可处理,则容器不会维护任何对象引用,因此当该对象被释放时,GC将立即回收它。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接