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 の原則を適用すると、多くの小規模で焦点を絞ったクラスが得られます。小さいので、コンストラクタを書くオーバーヘッドが大きくなります。

ただし、PostSharp などのコード ウィービング ツールを使用する代わりに、コンストラクターを生成する T4 テンプレートを作成することもできます。プロジェクトに T4 テンプレートを追加するT4ConstructorGenerator NuGet パッケージがあり、コンストラクターが生成されます。

このテンプレートでは、次のクラス:

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

テンプレートは部分クラスを追加することでこれを行うため、残りの元のコードは影響を受けません。テンプレートは、次の場合にのみコンストラクターを追加します。

  • クラス (および対応する部分クラス) にコンストラクターが定義されていません。
  • クラスは静的ではありません。
  • クラスには、1 つ以上のプライベート フィールドが含まれています。

コンストラクターに追加の初期化が含まれることが多い場合 (実際には、依存関係の挿入を行う場合はまれです)、OnCreated次のように、実際のクラスに部分メソッドを簡単に実装できます。

partial void OnCreated()
{
    // do logic here
}
于 2012-10-24T14:22:39.157 に答える
0

これは、PostSharp やその他の AOP ツールで確実に処理できるメソッドでの防御的なプログラミングにすぎませんが、そのコードを見ると、アーキテクチャで何か他の問題が発生している兆候のように思えます。

Inversion of Control コンテナー/依存性注入ツール (StructureMap、Ninject など) を使用していますか? もしそうなら、依存関係の配線を処理する必要があり、何かを配線するのを忘れると例外がスローされます。したがって、これにより、すべての防御的なプログラミングの必要性が減り、コンストラクターに他の初期化コードを入れることができます。

于 2012-10-25T13:29:26.610 に答える