C# 4.0 C#无法访问另一个类中注入依赖项的类的属性
我定义了以下C# 4.0 C#无法访问另一个类中注入依赖项的类的属性,c#-4.0,dependency-injection,unity-container,C# 4.0,Dependency Injection,Unity Container,我定义了以下处理器类: public class Processor : IProcessor { private IRepository _repository; private IMongoWrapper _mongoWrapper; public Processor(IRepository repository, IMongoWrapper mongoWrapper) { _repository = repository;
处理器
类:
public class Processor : IProcessor
{
private IRepository _repository;
private IMongoWrapper _mongoWrapper;
public Processor(IRepository repository, IMongoWrapper mongoWrapper)
{
_repository = repository;
_mongoWrapper = mongoWrapper;
}
public void Process()
{
_mongoWrapper.Initialise("path");
_repository.Save();
}
}
处理器
类在运行时被注入以下两个类:
public class MongoWrapper : IMongoRWrapper
{
private string _fileName;
public void Initialise(string path)
{
_fileName = path;
};
public void Log()
{
IsInitialised();
}
private void IsInitialised()
{
if (string.IsNullOrEmpty(_fileName))
throw new InvalidOperationException(
Resource.MongoRepositoryHelper_must_be_initialised);
}
}
public class Repository : IRepository
{
private IMongoWrapper _mongoWrapper;
public Repository(IMongoWrapper mongoWrapper)
{
_mongoWrapper = mongoWrapper;
}
public void Save()
{
_mongoWrapper.Log();
}
}
我使用Unity进行依赖注入
在Processor.Process()
方法中初始化的MongoWrapper
的属性\u fileName
,当我在Repository
类中访问该属性时不可用
谁能告诉我我做错了什么
当我将MongoWrapper
中的\u文件名
设置为静态字段时,它就工作了。这条路对吗
在中初始化的MongoWrapper
的属性\u fileName
Processor.Process()
方法在我访问
属性位于存储库类中
当您说不可用时,我假定您的意思是字符串\u fileName
没有被赋值。如果你的意思是别的,你可以忽略这个答案
未分配它的原因可能是因为您正在注入两个不同的引用,并使用默认的TransientLifetimeManager
在配置中注册类型时,或使用
RegisterType方法,默认行为由容器使用
一个短暂的终身管理者。它将创建
每次调用Resolve时注册、映射或请求的类型
或ResolveAll方法,或当依赖机制注入
实例转换为其他类
这意味着,当您解析处理器
时,它将获得一个MongoWrapper
实例,而当您解析存储库
时,您将获得另一个实例。每次注射都是新的
你可以这样想:
var processor = new Processor(new Repository(new MongoWrapper()), new MongoWrapper());
var mongoWrapper = new MongoWrapper();
var processor = new Processor(new Repository(mongoWrapper), mongoWrapper);
如您所见,它正在创建两个不同的MongoWrapper
。有几种方法可以解决这个问题
1.使用另一个LifetimeManager
PerResolveLifetimeManager
可能就是您想要的
对于此终身管理器,行为是
与TransientLifetimeManager类似,但也向
默认生成计划,标记类型以便重用实例
跨越构建对象图。在递归的情况下
单例行为适用于已向注册的对象
PerResolveLifetimeManager
这样注册:
container.RegisterType<IMongoWrapper, MongoWraper>(new PerResolveLifetimeManager());
2.使用containerControlled LifetimeManager
,将使您的IMongoWrapper
成为一个单例,因此始终使用相同的引用。根据您使用IMongoWrapper的方式,这可能是您想要的,也可能不是。在这种情况下,实际上就像将\u fileName
设置为静态
(如您所述),但是整个IMongoWrapper
是静态的
ContainerControlledLifetimeManager,用于注册现有对象
作为单个实例。在这一生中,manager Unity将返回
每次调用
Resolve或ResolveAll方法或当依赖机制注入时
实例转换为其他类
以及您的存储库:
public class Repository : IRepository
{
private IMongoWrapper _mongoWrapper;
public Repository()
{
}
public void SetWrapper(IMongoWrapper wrapper)
{
_mongoWrapper = wrapper;
}
public void Save()
{
_mongoWrapper.Log();
}
}
尽管如此,我必须说我同意你的设计。您真的需要将相同的IMongoWrapper
引用注入这两个类吗?而处理器
是否真的需要在IMongoWrapper
中设置一个值以使其可用于存储库
?它产生了一种奇怪的依赖,以后可能会再次困扰你。解决设计问题的答案可能更好,但我选择专注于实际任务
更新:
你认为哪一个是最好的解决方案?将lifetimemanager设置为
singleton还是在repository类中设置文件名的值
对我来说,听起来像是\u fileName
是一个上下文变量,它在一个请求/线程/周期中使用。因此,您可以相应地处理它。如果您真正想要的话,可以将mongowraper
设置为singleton。并让它负责保存\u filePath
但是,如果您只想将\u fileName
作为特定范围(例如线程或请求)的上下文变量,我写道,您可以从中使用代码。idéa是,您可以为\u fileName
共享一个容器,而不是依赖另一个特定的IMongoWrapper
引用。对于,请检入代码,这反过来又基于
首先是一个用于保存文件路径的类。它也可能只是一根绳子
public class ContextInfo : IContextInfo
{
public string FilePath {get; set;}
}
public interface IContextInfo
{
string FilePath {get; set;}
}
然后是使用IOperationContext
的包装器
现在变量已经设置好,您可以在任何地方使用它
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);
}
}
但同样,这完全取决于您倾向于如何使用文件名
,以及它的生命周期应该是什么。考虑变量的所有权。它是否应该属于IMongoWrapper
?或者它是整个应用程序中使用的东西。这些答案的问题应该引导你朝着正确的方向前进
在中初始化的MongoWrapper
的属性\u fileName
Processor.Process()
方法在我访问
属性位于存储库类中
当您说不可用时,我假定您的意思是字符串\u fileName
没有被赋值。如果你的意思是别的,你可以忽略这个答案
未分配它的原因可能是因为您正在注入两个不同的引用,并使用默认的TransientLifetimeManager
在配置中注册类型时,或使用
RegisterType方法,默认行为是
public class ContextInfo : IContextInfo
{
public string FilePath {get; set;}
}
public interface IContextInfo
{
string FilePath {get; set;}
}
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;
}
}
}
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);
}
}