Jef*_*eff 12 .net castle-windsor castle
我知道这已被讨论过了令人作呕......但我对Windsor跟踪Transient IDisposable对象的方式存在疑问.
我理解让Windsor管理我的IDiposables的好处......但我不喜欢它.
如果我想将我的组件包装在一个使用块中会发生什么?编码器会假设资源会在使用块结束时被清理掉,对吧?错误 - 将调用Dispose,但Windsor将保留实例直到明确释放.这对我来说一切都很好,因为我知道我在做什么......但是另一个编写类的开发人员想要使用IDisposable,通常使用其他IDisposable的方式 - 在一个使用块中呢?
using(factory.CreateInstance())
{
....
}
Run Code Online (Sandbox Code Playgroud)
看起来比我更清楚:
MyDisposable instance;
try
{
instance = factory.GetInstance();
}
finally
{
factory.Release(instance);
}
Run Code Online (Sandbox Code Playgroud)
为了真正处理我的实例并让它们符合GC的条件,我需要引用WindsorContainer或使用一个公开发布方法的类型工厂.这意味着使用IDisposable组件的唯一可接受的方法是使用类型化的工厂.在我看来,这并不好......如果有人将IDisposable接口添加到现有组件中会怎么样?每个需要注入组件的地方都需要改变.在我看来,这真的很糟糕.(当然,在非DI场景中,它还需要更改为调用Dispose ...但是对于Windsor,每个地方都需要更改以使用类型化工厂,这是一个更大的变化).
好的,公平的,我可以使用自定义的ReleasePolicy吗?这个怎么样?
public class CustomComponentsReleasePolicy : AllComponentsReleasePolicy
{
public override void Track(object instance, Burden burden)
{
if (burden.Model.LifestyleType == LifestyleType.Pooled)
base.Track(instance, burden);
}
}
Run Code Online (Sandbox Code Playgroud)
好的,很棒,我的IDisposable瞬态组件现在将是GC.
如果我想使用TypedFactory,那么我的类可以生成许多类型的实例,该怎么办?
public interface IMyFactory
{
MyDisposable GetInstance();
void Release(MyDisposable instance);
}
[Singleton]
public class TestClass
{
public TestClass(IMyFactory factory) { }
}
Run Code Online (Sandbox Code Playgroud)
好吧,对于一个,在工厂调用Release将无法在MyDisposable上调用Dispose(),因为MyDisposable没有被跟踪....
我怎样才能克服这些困难?
谢谢.
Mar*_*ius 10
首先,您如何知道与您未创建的对象相关的解构问题?你无法控制对象的创建,因为你没有自己创建它(工厂为你做了这个).当您将ioc解析与使用者处理(调用.Dispose而不是factory.Release)结合使用时,您将引入对象知道它是如何创建的要求,但它并没有创建自己.请考虑以下示例:
"组件"是您通过容器解决的问题,但您想要处理自己
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()
{
}
}
Run Code Online (Sandbox Code Playgroud)
如上所示,退役可能很复杂,我很简单,我看不出自己如何优雅地处理这个问题,特别是当温莎为我做这件事时.如果您的代码库充满了服务定位器反模式(http://blog.ploeh.dk/2010/02/03/ServiceLocatorisanAnti-Pattern/),我可以看到这是如何成为一个问题(我不是说你代码是),但那你真的有多大问题.
Run Code Online (Sandbox Code Playgroud)using(factory.CreateInstance()) { .... }看起来比我更清楚:......
那么using语句是一个约定,如果省略它就没有编译时错误,所以从我的观点来看,try/finally with release只是另一种约定,虽然有点冗长.例如,您可以通过创建帮助程序来缩短try/finally,例如:
[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;
}
}
}
Run Code Online (Sandbox Code Playgroud)
在我看来,这并不好......如果有人将IDisposable接口添加到现有组件中会怎么样?每个需要注入组件的地方都需要改变.
我不明白这个说法.组件的发布方式以及何时需要它是针对不同的问题,如果组件作为构造函数依赖项提供,则添加IDisposable不会更改任何内容.通过构造函数获取依赖关系的类没有创建它,因此不负责释放它.