3

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

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# 中默认的工作方式。

4

2 回答 2

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
}
于 2012-10-24T14:22:39.157 回答
0

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

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

于 2012-10-25T13:29:26.610 回答