Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/303.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何避免依赖注入构造函数的疯狂?_C#_Java_Dependency Injection_Inversion Of Control_Ioc Container - Fatal编程技术网

C# 如何避免依赖注入构造函数的疯狂?

C# 如何避免依赖注入构造函数的疯狂?,c#,java,dependency-injection,inversion-of-control,ioc-container,C#,Java,Dependency Injection,Inversion Of Control,Ioc Container,我发现我的构造函数开始像这样: public MyClass(Container con, SomeClass1 obj1, SomeClass2, obj2.... ) 随着参数列表的不断增加。既然“容器”是我的依赖注入容器,为什么我不能这样做: public MyClass(Container con) 每节课?缺点是什么?如果我这样做,感觉就像我在使用美化的静态。请分享您对IoC和依赖注入疯狂的看法。如果您将容器用作服务定位器,它或多或少是一个美化的静态工厂,这是正确的。有很多原因(也

我发现我的构造函数开始像这样:

public MyClass(Container con, SomeClass1 obj1, SomeClass2, obj2.... )
随着参数列表的不断增加。既然“容器”是我的依赖注入容器,为什么我不能这样做:

public MyClass(Container con)

每节课?缺点是什么?如果我这样做,感觉就像我在使用美化的静态。请分享您对IoC和依赖注入疯狂的看法。

如果您将容器用作服务定位器,它或多或少是一个美化的静态工厂,这是正确的。有很多原因(也可以从我的书中看到)

构造函数注入的一个极好的好处是,它使违反


当这种情况发生时,是时候采取行动了。简而言之,创建一个新的、更粗粒度的接口,该接口隐藏当前所需的部分或所有细粒度依赖项之间的交互。

我认为类构造函数不应该引用IOC容器周期。这表示类和容器之间存在不必要的依赖关系(IOC试图避免的依赖关系类型!)

传递参数的困难不是问题所在。问题是你的班级做得太多了,应该进一步细分


依赖项注入可以作为类变得太大的早期警告,特别是因为传递所有依赖项的痛苦越来越大。

您使用的是什么依赖项注入框架?您是否尝试过使用基于setter的注入

基于构造函数的注入的好处是,对于不使用DI框架的Java程序员来说,它看起来很自然。初始化一个类需要5件事,然后构造函数有5个参数。缺点是您已经注意到,当您有很多依赖项时,它会变得很笨拙

使用Spring,您可以使用setter传递所需的值,并且可以使用@required注释强制注入它们。缺点是,您需要将初始化代码从构造函数移动到另一个方法,并在注入所有依赖项后通过@PostConstruct标记Spring调用它。我不确定其他框架,但我认为它们也有类似的功能


这两种方法都有效,这是一个偏好问题。

我遇到了一个类似的问题,关于基于构造函数的依赖项注入,以及传递所有依赖项有多复杂

我过去使用的方法之一是使用服务层使用应用程序外观模式。这将有一个粗糙的API。若此服务依赖于存储库,它将使用私有属性的setter注入。这需要创建一个抽象工厂,并将创建存储库的逻辑移动到工厂中

详细的代码和解释可以在这里找到

问题:

1) 具有不断增加的参数列表的构造函数

2) 若继承了类(例如:
RepositoryBase
),则更改构造函数 签名导致派生类中的更改

解决方案1

将IoC容器传递给构造函数

为什么

  • 不再增加参数列表
  • 构造函数的签名变得简单
为什么不呢

  • 使类与IoC容器紧密耦合。(当1.您想在使用不同IoC容器的其他项目中使用该类时会出现问题。2.您决定更改IoC容器)
  • 使您的类不那么具有描述性。(您无法真正查看类构造函数并说出其功能所需的内容。)
  • 类可以潜在地访问所有服务
解决方案2

创建一个将所有服务分组的类,并将其传递给构造函数

 public abstract class EFRepositoryBase 
 {
    public class Dependency
    {
        public DbContext DbContext { get; }
        public IAuditFactory AuditFactory { get; }

         public Dependency(
            DbContext dbContext,
            IAuditFactory auditFactory)
        {
            DbContext = dbContext;
            AuditFactory = auditFactory;
        }
    }

    protected readonly DbContext DbContext;        
    protected readonly IJobariaAuditFactory auditFactory;

    protected EFRepositoryBase(Dependency dependency)
    {
        DbContext = dependency.DbContext;
        auditFactory= dependency.JobariaAuditFactory;
    }
  }
派生类

  public class ApplicationEfRepository : EFRepositoryBase      
  {
     public new class Dependency : EFRepositoryBase.Dependency
     {
         public IConcreteDependency ConcreteDependency { get; }

         public Dependency(
            DbContext dbContext,
            IAuditFactory auditFactory,
            IConcreteDependency concreteDependency)
        {
            DbContext = dbContext;
            AuditFactory = auditFactory;
            ConcreteDependency = concreteDependency;
        }
     }

      IConcreteDependency _concreteDependency;

      public ApplicationEfRepository(
          Dependency dependency)
          : base(dependency)
      { 
        _concreteDependency = dependency.ConcreteDependency;
      }
   }
为什么

  • 向类添加新的依赖项不会影响派生类
  • 类与IoC容器无关
  • 类是描述性的(在其依赖性方面)。按照惯例,如果您想知道
    A
    所依赖的类,则该信息将累积在
    A.Dependency
  • 构造函数签名变得简单
为什么不呢

  • 需要创建额外的类
  • 服务注册变得复杂(您需要分别注册每个
    X.Dependency
  • 概念上与传递
    IoC容器相同

不过,解决方案2只是一个原始的解决方案,如果有确凿的证据反对它,那么描述性的评论将不胜感激

这是我使用的方法

public class Hero
{

    [Inject]
    private IInventory Inventory { get; set; }

    [Inject]
    private IArmour Armour { get; set; }

    [Inject]
    protected IWeapon Weapon { get; set; }

    [Inject]
    private IAction Jump { get; set; }

    [Inject]
    private IInstanceProvider InstanceProvider { get; set; }


}
下面是一个粗略的方法,如何执行注入,并在注入值后运行构造函数。这是一个功能齐全的程序

public class InjectAttribute : Attribute
{

}


public class TestClass
{
    [Inject]
    private SomeDependency sd { get; set; }

    public TestClass()
    {
        Console.WriteLine("ctor");
        Console.WriteLine(sd);
    }
}

public class SomeDependency
{

}


class Program
{
    static void Main(string[] args)
    {
        object tc = FormatterServices.GetUninitializedObject(typeof(TestClass));

        // Get all properties with inject tag
        List<PropertyInfo> pi = typeof(TestClass)
            .GetProperties(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public)
            .Where(info => info.GetCustomAttributes(typeof(InjectAttribute), false).Length > 0).ToList();

        // We now happen to know there's only one dependency so we take a shortcut just for the sake of this example and just set value to it without inspecting it
        pi[0].SetValue(tc, new SomeDependency(), null);


        // Find the right constructor and Invoke it. 
        ConstructorInfo ci = typeof(TestClass).GetConstructors()[0];
        ci.Invoke(tc, null);

    }
}
公共类InjectAttribute:属性
{
}
公共类TestClass
{
[注入]
私有依赖关系sd{get;set;}
公共测试类()
{
控制台写入线(“ctor”);
控制台写入线(sd);
}
}
公共类依赖项
{
}
班级计划
{
静态void Main(字符串[]参数)
{
object tc=FormatterServices.GetUninitializedObject(typeof(TestClass));
//使用inject标记获取所有属性
列表pi=typeof(TestClass)
.GetProperties(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public)
.Where(info=>info.GetCustomAttributes(typeof(InjectAttribute),false).Length>0.ToList();
//我们现在碰巧知道只有一个依赖项,所以为了这个示例,我们选择了一个快捷方式,只设置值,而不检查它
pi[0].SetValue(tc,new-SomeDependency(),null);
//找到正确的构造函数并调用它。
ConstructorInfo ci=typeof(TestClass).GetConstructors()[0];
ci.Invoke(tc,null);
}
}
我目前正在做一个爱好项目,它是这样工作的
我把这整条线索读了两遍,然后
Container.GetSevice<MyClass>(someObject1, someObject2)