プロパティインジェクションのためのアノテーション位置を拡張する

日記でも何度か紹介しているが、Seasar2と同様のプロパティインジェクションで用いるアノテーション(カスタム属性)の宣言は、拙作の.NET用DIコンテナでも同様に、以下のように記述する。

public class HatenaUser
{
    [Binding(BindingType = BindingType.MUST, Value = "Kazzz")]
    public virtual string HandleName 
    {
        get { return this.handleName; }
        set { this.handleName= value; }
    }
}

そして、カスタム属性BindingAttributeクラスの定義は以下のようになっている。

[AttributeUsage(AttributeTargets.Property, Inherited = true, AllowMultiple = false)]
public class BindingAttribute : Attribute
{ 〜 }

つまり、プロパティの定義位置にアノテーション(面倒なので今後、アノテーションで統一する)を記述するのが決まりになる訳だ。このことは、派生クラスを作る際にアノテーションを再設定するためには、例え処理のオーバライドが不要であっても、以下のようにオーバライドの記述(橙色の部分)が強制されることを意味する。(そのために、プロパティ"HandleName"には前もってvirtualキーワードをつけている)

public class DelivedHatenaUser : HatenaUser
{
    [Binding(BindingType = BindingType.MUST, Value = "Kazzz2")]
    public override string HandleName 
    {
        get { return base.HandleName; }
        set { base.HandleName= value; }
    }
}

これではコード量を少なくするのが目的の一つだったはずのアノテーションが、逆にコードを増やしてしまう。Visual Studio 2005の場合、Intellisenseからoverrideを書くと上記のコードは自動的に生成されるが、そもそも不要なコードがあること自体気持ちが悪い。
そこで、カスタム属性BindingAttributeクラスを拡張してプロパティインジェクションのアノテーションを型に対しても宣言できるようにしてみた。

  • 新たなBindingAttributeクラスの宣言と、追加されたプロパティ
[AttributeUsage(AttributeTargets.Class| AttributeTargets.Property , Inherited = true, AllowMultiple = true)]
public class BindingAttribute : Attribute
{ 
    private string property;
    〜
    public string Property
    {
        get { return this.property; }
        set { this.property = value; }
    }
    〜
}

この新しいBindingAttributeにより、DelivedHatenaUserクラスにおける、プロパティインジェクションのためのアノテーションは、以下のように記述できるようになる。カスタム属性の使用属性であるAttributeUsageに"AttributeTargets.Class"が追加され、"AllowMultiple = true"により複数個のアノテーション定義が許可されるようになる。

  • プロパティインジェクションのためのアノテーションをクラス位置で宣言する例
[Binding(Property = "HandleName",Value = "Kazzz2")]
[Binding(Property = "MailAddress", Value = "Kazzz2@hogehoge.net.jp")]
[Binding(Property = "Phone", Value = "8165865854655")]
public class DelivedHatenaUser : HatenaUser
{
}

これでオーバライドのために発生していた、不要なコードを除去できるようになる。もちろん、従来どおりの宣言方法はそのまま有効なので、本当にオーバライドが必要な場合は元々の宣言方法を用いればよい。