使用内部方法注入依赖关系

时间:2015-02-04 23:00:30

标签: c# .net dependency-injection

我想在"平台"中定义一个注射依赖项。部件。我想要使​​用程序集来注入依赖项,但我不希望它们能够直接使用它。换句话说,我希望依赖本身是公开的,但依赖的方法是内部的。显然,您无法使用内部方法定义公共接口。

我想出了一个解决方案,但我想知道是否采用更清洁的方法。基本上,我不是定义一个接口,而是采用C ++启发的方法并定义一个纯抽象类。整件事情看起来像这样:

在"平台"组装

public abstract class IDependency
{
     public abstract void DoSomethingPublic();
     internal abstract void DoSomethingInternal();
}

public class DependencyImplementation : IDependency
{
     public override void DoSomethingPublic()
     {
          ...
     }

     public override void DoSomethingInternal()
     {
          ...
     }
}

public class Consumer
{
     public void Consume(IDependency dependency)
     {
          ...

          dependency.DoSomethingInternal();

          ...
     }
}

消费组装:

var consumer = new Consumer();
var dependency = new DependencyImplementation();
consumer.Consume(dependency);

这可以做我想要的一切,但它看起来像是一个hacky解决方案。是否有另一种解决这个问题的方法,或者这是一个可接受的解决方案?


修改:这是我实际问题的一个更具体的例子。我有一个平台组件和一个网站组件。在我的平台程序集中,我有以下扩展方法:

public static bool HasSettingEnabled(this IUser user, ISettingFactory factory)
{
     var settingEntity = factory.GetOrCreateByUserId(user.Id);
     return settingEntity.IsEnabled || user.ShouldForciblyEnableSetting;
}

在我的网站程序集中,我可以通过调用user.HasSettingEnabled()或直接从工厂获取设置来检查设置是否已启用。但是,我想限制网站程序集直接通过工厂检查设置,因为强制启用设置的逻辑将被遗漏。所以我希望我的ISettingFactory可以从网站上注入,但我不希望能够在平台之外调用ISettingFactory.GetOrCreateByUserId()。使用上面的模式,您可以获得以下内容:

平台组装:

public abstract class ISettingFactory
{
     internal abstract Setting GetOrCreateByUserId(int userId);
}

public class SettingFactory : ISettingFactory
{
     internal override Setting GetOrCreateByUserId(int userId)
     {
          // Get setting entity from DB
          ...
          return setting;
     }
}

public static class IUserExtension
{
    public static bool HasSettingEnabled(this IUser user, ISettingFactory factory)
    {
         var settingEntity = factory.GetOrCreateByUserId(user.Id);
         return settingEntity.IsEnabled || user.ShouldForciblyEnableSetting;
    }
}

在网站集中:

var settingFactory = new SettingFactory();
if (user.HasSettingEnabled(settingFactory))
{
     // Do something.
     ...
}

所以你可以看到网站只注入工厂而且永远不能直接获取或创建方法。这保证了只有一个代码路径可以获得用户的设置。

1 个答案:

答案 0 :(得分:1)

我不确定我100%理解你想要什么 - 是消费者提供的界面的实现吗?或者平台程序集是否包含IDependency的所有实现?在后一种情况下,也许内部接口可以提供帮助。

公共类可以实现内部接口。因此,您可以将所有内部方法放在内部接口中,将所有公共方法放在公共方法中,只暴露公众。这样,您可以在平台程序集中使用IInternalDependency,但只公开IDependency

public interface IDependency
{
     void DoSomethingPublic();
}

internal interface IInternalDependency : IDependency
{
    void DoSomethingInternal();
}

public class YourClass: IInternalDependency
{
   public void DoSomethingPublic() 
   {
   }

   // Note the Explicit interface member implementation
   void IInternalDependency.DoSomethingInternal()
   {
   }
}

在您的消费者代码中,您必须尝试投射它:

 public void Consume(IDependency dependency)
 {    
      var intDependency = dependency as IInternalDependency;
      if(intDependency == null)
      {
         throw new InvalidOperationException();
      }
      intDependency.DoSomethingInternal();
 }