的属性,在初始化 Processor.Process()
方法的MongoWrapper
_fileName
不可用,当我在Repository
类访问 属性。
当你说不可,我认为你的意思是字符串_fileName
尚未分配的值。如果你的意思是别的,你可能会忽略这个答案。
它没有被分配的原因可能是因为你注入了两个不同的引用,并且使用了默认的TransientLifetimeManager
。
Understanding Lifetime Managers
当注册在结构的类型,或通过使用 RegisterType方法,默认行为是容器使用 瞬态寿命管理器。每次调用Resolve 或ResolveAll方法或依赖关系机制将 实例注入其他类时,它会创建一个新的 注册,映射或请求类型实例。
这意味着,当你解决Processor
它会得到的MongoWrapper
一个实例,当你解决Repository
你会得到另一个。它在每次注射时都会出现。
把它看成是这样的:
var processor = new Processor(new Repository(new MongoWrapper()), new MongoWrapper());
正如你看到的,它创建了两个不同的MongoWrapper
。有几种方法可以解决这个问题。
1.使用另一个LifetimeManager
。 PerResolveLifetimeManager
可能是你想要的。
对于这个寿命管理器的行为是 像TransientLifetimeManager,而且还提供了一个信号给 默认的构建方案,标记的类型,使得实例重用 横跨积聚对象图。在递归的情况下, 单身行为适用于对象已注册到PerResolveLifetimeManager的 。
注册它像这样:它
container.RegisterType<IMongoWrapper, MongoWraper>(new PerResolveLifetimeManager());
这样想:
var mongoWrapper = new MongoWrapper();
var processor = new Processor(new Repository(mongoWrapper), mongoWrapper);
2.使用ContainerControlledLifetimeManager
,会让你的IMongoWrapper
单身,因此使用始终是相同的参考。根据你使用IMongoWrapper的方式,这可能会或可能不会成为你想要的。在这种情况下,它可能会像设置_fileName
为static
(如您所述),但整个IMongoWrapper
是static
。
ContainerControlledLifetimeManager将现有对象 注册为单例实例。对于此生存期管理器,每次调用 Resolve或ResolveAll方法或当依赖关系机制将 实例注入到其他类中时,Unity管理器会返回 相同的注册类型或对象实例。
container.RegisterType<IMongoWrapper, MongoWraper>(new ContainerControlledLifetimeManager());
3.分配IMongoWrapper
手动。但是,这会破坏使用IoC的全部目的。
public class Processor : IProcessor
{
private IRepository _repository;
private IMongoWrapper _mongoWrapper;
public Processor(IRepository repository, IMongoWrapper mongoWrapper)
{
_repository = repository;
_mongoWrapper = mongoWrapper;
_repository.SetWrapper(mongoWrapper);
}
public void Process()
{
_mongoWrapper.Initialise("path");
_repository.Save();
}
}
而且你的资料库:
public class Repository : IRepository
{
private IMongoWrapper _mongoWrapper;
public Repository()
{
}
public void SetWrapper(IMongoWrapper wrapper)
{
_mongoWrapper = wrapper;
}
public void Save()
{
_mongoWrapper.Log();
}
}
与所有的说,我必须说,我Steven关于你的设计一致。你真的需要在两个类中注入相同的参考IMongoWrapper
吗?并且Processor
真的需要在IMongoWrapper
中设置一个值才能使其可用于Repository
?它造成了一种奇怪的依赖,可能会在以后再次出现。解决设计问题的答案可能会更好,但我选择专注于实际任务。
UPDATE:
是最好的解决方案,你认为哪一个?要将生存管理器设置为 单例,或者在存储库类中设置文件名的值?
嗯,对我来说听起来像_fileName
是一个上下文变量,它在整个一个请求/线程/循环中使用。因此你可以相应地处理它。或者将MongoWrapper
设置为单身,如果这就是您实际需要的。并让它负责保留_filePath
。
但是,如果您只是想保留_fileName
作为特定范围(例如线程或请求)的上下文变量,我写了an answer for a similiar question,您可以从中使用该代码。该idéa是,而不是依靠另一个具体的参考IMongoWrapper
,你可以共享一个容器_fileName
。对于IOperationContext
,请检查the answer I wrote中的代码,该代码依次基于this question。
首先保存FilePath的类。它可能只是一个字符串。
public class ContextInfo : IContextInfo
{
public string FilePath {get; set;}
}
public interface IContextInfo
{
string FilePath {get; set;}
}
然后使用IOperationContext<IContextInfo>
的包装。
public class RequestContext : IRequestContext
{
private readonly IOperationContext<IContextInfo> _operationContext;
public RequestContext(IOperationContext<IContextInfo> operationContext)
{
_operationContext = operationContext;
}
public IContextInfo ContextInfo
{
get
{
if (_operationContext.Items.ContainsKey("ContextInfoString"))
{
return _operationContext.Items["ContextInfoString"];
}
return null;
}
set
{
_operationContext.Items["ContextInfoString"] = value;
}
}
}
将IRequestContext
注入您的处理器。
public class Processor : IProcessor
{
private IRepository _repository;
private IMongoWrapper _mongoWrapper;
private IRequestContext _requestContext
public Processor(IRepository repository, IMongoWrapper mongoWrapper, IRequestContext requestContext)
{
_requestContext = requestContext
_repository = repository;
_mongoWrapper = mongoWrapper;
}
public void Process()
{
// Set the context variable.
_requestContext.ContextInfo = new ContextInfo { FilePath = "path" });
// Now it will be set for a specific lifetime.
_repository.Save();
}
}
现在变量设置,您可以随时随地使用它...
public class MongoWrapper : IMongoRWrapper
{
private IRequestContext _requestContext;
public MongoWrapper(IRequestContext requestContext)
{
_requestContext = requestContext;
}
private void IsInitialised()
{
if (string.IsNullOrEmpty(_requestContext.ContextInfo.FilePath))
throw new InvalidOperationException(
Resource.MongoRepositoryHelper_must_be_initialised);
}
}
但同样,这一切都取决于你会如何使用fileName
,以及它的生命周期应该是。考虑变量的所有权。它应该归IMongoWrapper
所有?或者它是在整个应用程序中使用的东西。这些答案的问题应引导你朝着正确的方向发展。
为什么你需要'Process'来传递'MongoWrapper'的路径?该设计闻起来。 – Steven
流程方法实际上是由Windows服务调用的,路径是服务从文件夹位置获取的文件名。所以它总是变化。 –
因此,每次调用'Proces'方法时会有所不同,还是这个配置值在Windows服务运行时不会改变? – Steven