Dependency injection 有没有办法使用PostSharp使构造函数参数在类级别可见?

Dependency injection 有没有办法使用PostSharp使构造函数参数在类级别可见?,dependency-injection,constructor,postsharp,aop,Dependency Injection,Constructor,Postsharp,Aop,假设我有很多这样的样板代码: class MyClass { private readonly IDependencyA dependencyA; private readonly IDependencyB dependencyB; public MyClass( IDependencyA dependencyA, IDependencyB dependencyB) { if(dependencyA == null

假设我有很多这样的样板代码:

class MyClass
{
    private readonly IDependencyA dependencyA;
    private readonly IDependencyB dependencyB;

    public MyClass(
        IDependencyA dependencyA,
        IDependencyB dependencyB)
    {
        if(dependencyA == null) throw ArgumentNullException("dependencyA");
        if(dependencyB == null) throw ArgumentNullException("dependencyB");
        this.dependencyA = dependencyA;
        this.dependencyB = dependencyB;

        ...
    }

    ...

    public void SomeMethod()
    {
        this.dependencyA.DoSomething(this.dependencyB);
    }
}
class MyClass
{
    [ConstructorParametersAreClassMembers]
    public MyClass(
        IDependencyA dependencyA,
        IDependencyB dependencyB)
    {
        ...
    }

    ...

    public void SomeMethod()
    {
        this.dependencyA.DoSomething(this.dependencyB);
    }
}
有没有一种方法可以使用类似PostSharp的东西来删除样板代码并使其看起来像这样:

class MyClass
{
    private readonly IDependencyA dependencyA;
    private readonly IDependencyB dependencyB;

    public MyClass(
        IDependencyA dependencyA,
        IDependencyB dependencyB)
    {
        if(dependencyA == null) throw ArgumentNullException("dependencyA");
        if(dependencyB == null) throw ArgumentNullException("dependencyB");
        this.dependencyA = dependencyA;
        this.dependencyB = dependencyB;

        ...
    }

    ...

    public void SomeMethod()
    {
        this.dependencyA.DoSomething(this.dependencyB);
    }
}
class MyClass
{
    [ConstructorParametersAreClassMembers]
    public MyClass(
        IDependencyA dependencyA,
        IDependencyB dependencyB)
    {
        ...
    }

    ...

    public void SomeMethod()
    {
        this.dependencyA.DoSomething(this.dependencyB);
    }
}
这可能吗


旁白:这实际上是F#中默认的工作方式。

这是可能的,但不是一个非常吸引人的方法。我理解痛苦。我觉得C#在这一点上有点冗长。当你运用这些坚实的原则时,你会得到许多小而集中的课程。因为它们很小,所以编写构造函数的开销越来越大

但是,您也可以创建一个T4模板来为您生成构造函数,而不是使用PostSharp之类的代码编织工具。有一个NuGet包,它将T4模板添加到您的项目中,从而为您生成一个构造函数

使用此模板可以创建以下类:

公共类服务
{
私有只读ITimeProvider timeProvider;
专用只读ILogger记录器;
专用只读计算器;
私有只读IMailSender mailSender;
公共方法()
{
//使用依赖项
}
}
将获得以下构造函数:

公共服务(
ITimeProvider时间提供程序,
ILogger记录器,
IOrderCalculator,
i邮件发送者(邮件发送者)
{
如果(timeProvider==null)抛出新的ArgumentNullException(“timeProvider”);
如果(logger==null)抛出新的ArgumentNullException(“logger”);
如果(calculator==null)抛出新的ArgumentNullException(“calculator”);
如果(mailSender==null)抛出新的ArgumentNullException(“mailSender”);
this.timeProvider=timeProvider;
this.logger=记录器;
this.calculator=计算器;
this.mailssender=mailssender;
this.OnCreated();
}
部分空白一经处理();
模板通过添加一个分部类来实现这一点,因此其他原始代码不会受到影响。模板仅在以下情况下添加构造函数:

  • 该类(及其对应的部分类)没有定义任何构造函数
  • 这个类不是静态的
  • 该类包含一个或多个私有字段
在构造函数通常包含额外初始化的情况下(在执行依赖项注入时,这实际上应该很少),您只需在实际类中实现partial
OnCreated
方法,如下所示:

partial void OnCreated()
{
    // do logic here
}

这只是一种方法中的防御性编程,PostSharp或其他AOP工具当然可以处理,但我查看了这些代码,它似乎是架构中出现其他问题的征兆


您是否正在使用控制容器/依赖项注入工具的反转(如StructureMap、Ninject等)?如果是这样,那么它应该为您处理关联依赖项,如果您忘记关联某些内容,它将抛出异常。因此,这减少了对所有防御性编程的需要,同时仍然允许您在构造函数中放置其他初始化代码。

这很酷,但是如果我需要在构造函数中运行其他类型的初始化代码,会发生什么呢?也许我可以修改它,让它调用一个
私有的
无参数构造函数,这是我被迫实现的;它不会改变原始类(除非它可能将该类标记为“partial”)。如果需要“自定义”构造函数,只需将其添加到类中,生成的构造函数就会消失。顺便说一句,在执行依赖项注入时,在服务类中进行任何其他初始化应该是非常不寻常的。当然,但我的构造函数中可能有90%都在构造函数中进行初始化,所以这不起作用。我意识到它无法在原始文件中创建构造函数,但在我添加一个构造函数之前,它将无法编译。在决定要为哪些类添加部分类时,您必须修改T4脚本以忽略私有构造函数……我并不是说这种方法适用于每个类,您可能需要一些tweek才能使其适用于您的情况,但使用PostSharp可能会更难。在我的应用程序中,这适用于95%的类。我想知道你为什么要在构造函数中进行这么多初始化。Scott试图解决的问题是消除C#编译器给我们的冗长。当您遵循SRP时,类会变小,编写构造函数的开销也会变大。但我必须承认,我通常不会从构造函数中编写任何保护子句,因为我的DI容器将保证注入非null值。但是,所有这些构造函数参数都必须映射到私有实例字段。我真的很喜欢C#在这个领域的发展,但我知道这个功能永远不会被添加。