1

我有一个被许多 MVC 应用程序使用的 UserModel 类,我试图将其转换为使用 IoC:

public class UserModel
{
    public string Login { get; set; }

    [DisplayName("Display Name")]
    public string DisplayName { get; set; }

    public static explicit operator UserModel(string userLogin)
    {
        IKernel IoC; // Where do I get this from?
        var ActiveDirRepo = IoC.Get<IActiveDirectoryRepository>();

        var User = ActiveDirRepo.FindById<ActiveDirectoryUser>(userLogin.ToUpper());

        return new UserModel()
        {
            Login = userLogin,
            DisplayName = User == null ? userLogin.ToUpper() : User.Name
        };
    }
}

它有一个从stringto的显式转换运算符UserModel。以前我只是new编辑ActiveDirectoryRepository并使用它,但我想开始使用 IoC/DI。

我现在遇到的问题是,我如何引用我的 IoC 容器(IKernel)?

我无法从外部将其注入UserModel,因为操作员正在创建它。

4

4 回答 4

1

您可以使用Microsoft.Practices.ServiceLocation形式的服务定位器模式,如果 ninject 不提供实现,我会感到惊讶。如果没有,则直接实施。

不管你可以用这段代码做你想做的事,我强烈建议你不要像你那样实现显式转换运算符。这是一种不好的做法。

于 2013-09-30T07:54:34.163 回答
1

IoC 没有魔法。有时您仍然需要一个起点,您可以从该起点访问应用程序的 IoC 容器,如下所示:

var ioc = Application.Instance.Container.Get<IActiveDirectoryRepository>();

您不需要从任何地方访问 IoC 容器,因为通过容器创建的对象已经注入了它们的依赖项,但至少一些根对象需要获得对容器的访问权限。

于 2013-09-30T07:56:16.077 回答
1

从意识形态上讲,您的 IoC 容器应该只存在于应用程序的复合根目录中。考虑到这一点,这是一个找出类依赖关系并通过构造函数注入它们的问题(如果你不能执行构造函数 DI,那么许多 IoC 容器提供了替代的注入方法)。

在这里,您需要访问IActiveDirectoryRepository才能创建 UserModel。但是,您的创建方法explicit operator UserModel是一个静态方法,无法访问实例变量。不幸的是,这限制了您使用依赖注入来利用 IoC 的能力,所以这里有一些想法:

  • 直截了当:使用服务定位器模式。您使用服务定位器来获取IActiveDirectoryRepository. 这将直接很好地适应您当前的实现(将内核行交换到服务定位器)。但是,这种模式也有缺点;最值得注意的是,您正在内化您的IActiveDirectoryRepository源代码,这将使单元测试的效率降低。

  • 传统:使您的UserModel创建者成为通过其构造函数接受的工厂IActiveDirectoryRepository。然后,UserModel工厂创建的任何 ' 都使用提供的IActiveDirectoryRepository.

    public sealed class UserFactory
    {
        private readonly IActiveDirecotryRepository repository;
        public UserFactory(IActiveDirectoryRepository repository)
        {
            this.repository = repository;
        }
    
        public UserModel CreateNewUser(string userLogin)
        {
            var User = repository.FindById<ActiveDirectoryUser>(userLogin.ToUpper());
            return new UserModel()
            {
                Login = userLogin,
                DisplayName = User == null ? userLogin.ToUpper() : User.Name
            } 
        }
    }
    
  • 花式:创建一个闭包IActiveDirectoryRepository并将创建者作为一流函数传递。

    static Func<string, UserModel> CreateFactory(IActiveDirectoryRepository repository)
    {
        return (userLogin) => 
        {
            var User = repository.FindById<ActiveDirectoryUser>(userLogin.ToUpper());
            return new UserModel()
            {
                Login = userLogin,
                DisplayName = User == null ? userLogin.ToUpper() : User.Name
            }   
        }
    }
    
于 2013-09-30T09:06:22.547 回答
1

这种转换假设很简单,不需要外部依赖。如果你需要注入某种依赖,然后忘记转换,没有解决办法。

很简单,将 IKernel 传递给构建方法:

public static UserModel Build(string userLogin, IKernel IoC)
{
    var ActiveDirRepo = IoC.Get<IActiveDirectoryRepository>();

    var User = ActiveDirRepo.FindById<ActiveDirectoryUser>(userLogin.ToUpper());

    return new UserModel()
    {
        Login = userLogin,
        DisplayName = User == null ? userLogin.ToUpper() : User.Name
    };
}

然后你可以问问自己,这个方法属于 IKernel 接口是否有意义:

interface IKernel
{
    UserModel Build(string userLogin);
}
于 2013-09-30T07:57:55.053 回答