如何在不同时间跨组件图共享临时对象?
我有一些来自旧遗留代码的状态引擎。每个州都由IState代表,负责在流程中创建下一个州。
public interface IState
{
Guid Session { get; }
IState GetNextState();
}
起始状态由模型初始化:
public class Model
{
private readonly IStateFactory _stateFactory;
public Model(IStateFactory stateFactory)
{
_stateFactory = stateFactory;
}
public IState GetFirstState()
{
return _stateFactory.GetStateA();
}
}
每个州都包含一个会话上下文(简化为仅包含GUID)。
public class Context : IDisposable
{
public static int CreatedCount = 0;
public static int DisposedCount = 0;
//Has other DI injected dependencies.
public Context()
{
CreatedCount++;
}
public Guid SessionGuid { get; } = Guid.NewGuid();
public void Dispose()
{
DisposedCount++;
}
}
已添加“CreatedCount”和“DisposedCount”以帮助演示此问题。请注意,它们是静态整数。
国家的实施可能是这样的:
public class MyState : IState
{
private readonly Context _context;
private readonly IStateFactory _stateFactory;
public MyState(IStateFactory stateFactory, Context context)
{
_context = context;
_stateFactory = stateFactory;
}
public Guid Session => _context.SessionGuid;
public IState GetNextState()
{
var nextState = _stateFactory.GetStateB(_context);
_stateFactory.DestroyState(this);
return nextState;
}
}
州工厂是一个简单的Castle Windsor实施的TypedFactory界面。
public interface IStateFactory
{
IState GetFirstState();
IState GetStateB(Context context);
void DestroyState(IState state);
}
这个想法是每个“状态”可以基于某个动作启动下一个状态,并且当前状态“上下文”应该在下一个状态中使用。
容器以预期的方式构建:
var container = new WindsorContainer();
container.AddFacility<TypedFactoryFacility>();
container.Register(
Component.For<Context>().LifestyleTransient(),
Component.For<IState>().ImplementedBy<MyState>().Named("stateA").LifestyleTransient(),
Component.For<IState>().ImplementedBy<MyState>().Named("stateB").LifestyleTransient(),
Component.For<IStateFactory>().AsFactory()
);
基本上,我希望“stateB”获得Context的所有权。但是当我发布“stateA”(通过调用MyState.GetNextState)时,Context被释放并处理掉!我如何告诉Castle.Windsor将所有权转移到下一个州?
var model = container.Resolve<Model>();
var initialState = model.GetFirstState();
var nextState = initialState.GetNextState(); //releases the initial State.
Assert.That(initialState.Session, Is.EqualTo(nextState.Session)); //The context was 'shared' by stateA by passing it into the factory method for stateB.
Assert.That(Context.CreatedCount, Is.EqualTo(1));
Assert.That(Context.DisposedCount, Is.EqualTo(0)); //FAIL! Castle Windsor should see that the shared "Context" was passed into the constructor of modelB, and added a reference to it.
container.Release(model);
container.Release(nextState); //usually done by the model.
Assert.That(Context.CreatedCount, Is.EqualTo(1));
Assert.That(Context.DisposedCount, Is.EqualTo(1));
应该注意,状态转换可以从另一个线程启动,但在创建线程上调用。这会扰乱默认的Castle Windsor范围生活方式所使用的CallContext。这适用于桌面应用程序,因此默认WCF和Web请求范围生活方式不适用。
答案 0 :(得分:1)
使用public partial class MainWindow : Window
{
public static StatusInfo status;
public MainWindow()
{
InitializeComponent();
SourceInitialized += MainWindow_SourceInitialized;
}
private void MainWindow_SourceInitialized(object sender, EventArgs e)
{
SetUpDisplay();
}
private void SetUpDisplay()
{
status = new StatusInfo();
}
}
:
LifestyleScoped
答案 1 :(得分:0)
我已经提出了另一个解决这个问题的方法,这个问题适用于Castle Windsors范围没有的地方。我创造了一种生活方式,只要通过使用引用计数来使用它就能保持单身。一旦引用计数变为0,就释放该对象。
npm i @types/fullcalendar -s
它的用法如下:
public class ReferenceCountedSingleton : AbstractLifestyleManager, IContextLifestyleManager
{
private readonly object _lock = new object();
private Burden _cachedBurden;
private int _referenceCount;
public override void Dispose()
{
var localInstance = _cachedBurden;
if (localInstance != null)
{
localInstance.Release();
_cachedBurden = null;
}
}
public override object Resolve(CreationContext context, IReleasePolicy releasePolicy)
{
lock(_lock)
{
_referenceCount++;
if (_cachedBurden != null)
{
Debug.Assert(_referenceCount > 0);
return _cachedBurden.Instance;
}
if (_cachedBurden != null)
{
return _cachedBurden.Instance;
}
var burden = CreateInstance(context, false);
_cachedBurden = burden;
Track(burden, releasePolicy);
return burden.Instance;
}
}
public override bool Release(object instance)
{
lock (_lock)
{
if (_referenceCount > 0) _referenceCount--;
if (_referenceCount > 0) return false;
_referenceCount = 0;
_cachedBurden = null;
return base.Release(instance);
}
}
protected override void Track(Burden burden, IReleasePolicy releasePolicy)
{
burden.RequiresDecommission = true;
base.Track(burden, releasePolicy);
}
public object GetContextInstance(CreationContext context)
{
return context.GetContextualProperty(ComponentActivator);
}
}