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);
    }
}