有没有办法使用PostSharp在类级别显示构造函数参数?

时间:2012-10-24 14:09:48

标签: dependency-injection constructor postsharp aop

说我有很多这样的样板代码:

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

有没有办法使用像PostSharp这样的东西来删除样板代码并使它看起来像这样:

class MyClass
{
    [ConstructorParametersAreClassMembers]
    public MyClass(
        IDependencyA dependencyA,
        IDependencyB dependencyB)
    {
        ...
    }

    ...

    public void SomeMethod()
    {
        this.dependencyA.DoSomething(this.dependencyB);
    }
}

这甚至可能吗?

除此之外:这实际上是它在F#中的默认工作方式。

2 个答案:

答案 0 :(得分:3)

这是可能的,但不是一种非常有吸引力的方法。我理解痛苦。我觉得C#在这一点上有点冗长。在应用SOLID原则时,您会获得许多小型和专注的课程。由于它们很小,编写构造函数的开销变得更大。

但是,您可以创建一个为您生成构造函数的T4模板,而不是使用PostSharp等代码编织工具。有一个T4ConstructorGenerator NuGet包,可以为你的项目添加一个T4模板,为你生成一个构造函数。

使用此模板,可以使用以下类:

public class SomeService
{
    private readonly ITimeProvider timeProvider;
    private readonly ILogger logger;
    private readonly IOrderCalculator calculator;
    private readonly IMailSender mailSender;

    public void SomeMethod()
    {
        // using the dependencies
    }
}

将获得以下构造函数:

    public SomeService(
        ITimeProvider timeProvider,
        ILogger logger,
        IOrderCalculator calculator,
        IMailSender mailSender)
    {
        if (timeProvider == null) throw new ArgumentNullException("timeProvider");
        if (logger == null)  throw new ArgumentNullException("logger");
        if (calculator == null) throw new ArgumentNullException("calculator");
        if (mailSender == null) throw new ArgumentNullException("mailSender");

        this.timeProvider = timeProvider;
        this.logger = logger;
        this.calculator = calculator;
        this.mailSender = mailSender;

        this.OnCreated();
    }

    partial void OnCreated();

模板通过添加部分类来完成此操作,因此其他原始代码不会受到影响。模板只会在以下时间添加构造函数:

  • 类(及其相应的部分类)没有定义任何构造函数。
  • 班级不是静态的。
  • 该类包含一个或多个私有字段。

如果您的构造函数通常包含额外的初始化(实际上在执行依赖注入时应该很少),您可以在实际类中实现部分OnCreated方法,如下所示:

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

答案 1 :(得分:0)

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

您使用的是Inversion of Control容器/依赖注入工具(如StructureMap,Ninject等)吗?如果是这样,那么它应该为您处理依赖关系,如果您忘记连接某些内容,它将抛出异常。因此,这减少了对所有防御性编程的需求,同时仍允许您在构造函数中放入其他初始化代码。