首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >温莎城堡

温莎城堡
EN

Stack Overflow用户
提问于 2011-07-21 20:34:18
回答 2查看 3.9K关注 0票数 12

我知道这已经被讨论过了,nauseum...but,我对温莎跟踪瞬态IDisposable对象的方式有一个问题。

我理解让温莎管理我的IDiposables...but的好处,我不喜欢它。

如果我想将组件封装在一个使用的块中,会发生什么?编码器会假设资源会在使用块的末尾被清理,对吗?错误-处置将被调用,但温莎将保持实例直到显式释放。对于我来说,这一切都很好,因为我知道我是doing...but,那么另一个正在编写类并希望像其他IDisposable一样使用IDisposable的开发人员呢?

代码语言:javascript
运行
复制
using(factory.CreateInstance()) 
{
   ....  
}

在我看来比:

代码语言:javascript
运行
复制
MyDisposable instance;
try
{
    instance = factory.GetInstance();
}
finally 
{
    factory.Release(instance);
}

为了真正地释放我的实例并使它们符合GC的条件,我需要引用WindsorContainer或者使用一个公开发布方法的类型化工厂。这意味着使用IDisposable组件的唯一可接受的方法是使用类型化工厂。这在我的opinion...what中是不好的,如果有人将IDisposable接口添加到现有组件中?每个期望注入组件的地方都需要改变。在我看来,确实很糟糕。(当然,在非DI场景中,需要更改使用类型工厂,这是一个大得多的更改,需要用温莎调用Dispose also...but,每个地方都需要更改。)

好吧,很公平,我可以使用定制的ReleasePolicy,对吗?这个怎么样?

代码语言:javascript
运行
复制
public class CustomComponentsReleasePolicy : AllComponentsReleasePolicy
{
    public override void Track(object instance, Burden burden)
    {
        if (burden.Model.LifestyleType == LifestyleType.Pooled) 
            base.Track(instance, burden);
    }
}

好吧,太好了,我的IDisposable瞬态组件现在是GC了。

如果我想要使用一个TypedFactory,以便我的类能够生成一个类型的许多实例,该怎么办?

代码语言:javascript
运行
复制
public interface IMyFactory 
{
    MyDisposable GetInstance();
    void Release(MyDisposable instance);
}

[Singleton]
public class TestClass
{
    public TestClass(IMyFactory factory) { }
}

好吧,首先,在工厂上调用发布版对调用MyDisposable上的Dispose()没有任何作用,因为MyDisposable没有被跟踪.

我怎样才能克服这些困难?

谢谢。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2011-10-28 06:42:58

首先,您如何知道与您没有创建的对象相关的反分解关注点?您无法控制对象的创建,因为您没有自己创建对象(工厂为您创建了该对象)。当将ioc解析与消费者处理(调用.Dispose而不是factory.Release)结合起来时,您将引入这样的要求:对象知道如何创建它,但它没有创建自己。请考虑以下示例:

“组件”是您通过容器解决的问题,但是您希望自己处理掉。

代码语言:javascript
运行
复制
public class Component : IDisposable
{
    private readonly IAmSomething _something;

    public Component(IAmSomething something)
    {
        _something = something;
    }

    public void Dispose()
    {
        // Problem 1: the component doesnt know that an implementation of IAmSomething might be disposable
        // Problem 2: the component did not create "something" so it does not have the right to dispose it
        // Problem 3: What if an implementation of "something" has a depenency on a disposable instance deep down in its object graph?

        // this is just bad..
        IDisposable disposable = _something as IDisposable;

        if (disposable != null)
            disposable.Dispose();

    }
}

public interface IAmSomething
{

}

public class SomethingA : IAmSomething
{

}

public class SomethingB : IAmSomething, IDisposable 
{
    public void Dispose()
    {
    }
}

如上文所示,退役可能很复杂,我不知道如何自己优雅地处理这一问题,尤其是当温莎为我这样做的时候。如果您的代码库中到处都是服务定位器反模式(http://blog.ploeh.dk/2010/02/03/ServiceLocatorisanAnti-Pattern/),我可以看到这是如何成为一个问题的(我并不是说您的代码是这样的),但是您确实有很多更大的问题。

使用(factory.CreateInstance()){.}

在我看来比…要清楚得多

using语句是一种约定,如果省略它,就不会出现编译时错误,所以在我看来,try/只是另一种约定,尽管更详细一些。例如,您可以通过创建一个助手来缩短try/finally,例如:

代码语言:javascript
运行
复制
[TestFixture]
public class SomeCastleTests
{
    [Test]
    public void Example()
    {
        var container = new WindsorContainer();

        // you would of course use a typed factory instead in real word

        using (var usage = new ComponentUsage<IAmSomething>(container.Resolve<IAmSomething>, container.Release))
        {
            // use..
            usage.Component
        }
    }
}

public class ComponentUsage<T> : IDisposable where T : class
{
    private Func<T> _create;
    private Action<T> _release;

    private T _instance;

    public ComponentUsage(Func<T> create, Action<T> release)
    {
        _create = create;
        _release = release;
    }

    public T Component
    {
        get
        {
            if (_instance == null)
                _instance = _create();

            return _instance;
        }
    }

    public void Dispose()
    {
        if (_instance != null)
        {
            _release(_instance);
            _instance = null;
        }
    }
}

如果有人将

接口添加到现有组件中,那么在我的opinion...what中,这是不好的吗?每一个期望组件被注入的地方都需要改变。

我不明白这句话。如果组件是作为构造函数依赖提供的,那么添加IDisposable不会改变任何事情。通过构造函数获得依赖关系的类没有创建它,因此不负责释放它。

票数 12
EN

Stack Overflow用户

发布于 2014-07-18 22:58:49

作为一个小猪背,您可以通过创建一个为您释放对象的拦截器来解决您提到的其他一些问题。我这么做是为了一个工作单位。拦截器看起来如下:

代码语言:javascript
运行
复制
public class UnitOfWorkReleaseOnDispose : IInterceptor
{
    private readonly IUnitOfWorkFactory unitOfWorkFactory;

    public UnitOfWorkReleaseOnDispose(IUnitOfWorkFactory unitOfWorkFactory)
    {
        this.unitOfWorkFactory = unitOfWorkFactory;
    }

    public void Intercept(IInvocation invocation)
    {
        invocation.Proceed();
        this.unitOfWorkFactory.DestroyUnitOfWork((IUnitOfWork)invocation.Proxy);
    }
}

我的注册代码如下:

代码语言:javascript
运行
复制
            Component.For<IUnitOfWork>()
                .ImplementedBy<TransactionalUnitOfWork>()
                .LifestyleTransient()
                .Interceptors<UnitOfWorkReleaseOnDispose>()
                    .Proxy.Hook(h => h.Service<InterfaceMethodsOnlyProxyGenerationHook<IDisposable>>())

代理钩子只表示我只想代理IDiposable接口方法。这门课是这样的:

代码语言:javascript
运行
复制
public class InterfaceMethodsOnlyProxyGenerationHook<TInterface> : IProxyGenerationHook
{
    public void MethodsInspected()
    {

    }

    public void NonProxyableMemberNotification(Type type, System.Reflection.MemberInfo memberInfo)
    {

    }

    public bool ShouldInterceptMethod(Type type, System.Reflection.MethodInfo methodInfo)
    {
        return typeof(TInterface) == type;
    }
}

它还需要注册,因为我使用的是我使用的钩子重载:

代码语言:javascript
运行
复制
            Component.For<IProxyGenerationHook>()
                .ImplementedBy<InterfaceMethodsOnlyProxyGenerationHook<IDisposable>>()
                .LifestyleSingleton()
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/6782400

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档