DOBON.NET DOBON.NETプログラミング掲示板過去ログ

クラスに動的にカスタム属性を追加するには?

環境/言語:[VB.NET .NET Framework 2.0 Windows 7]
分類:[.NET]

こんにちは。

インスタンスしたクラスから、
カスタム属性を参照することはできるのですが、
動的にカスタム属性の追加・更新する方法が分かりません。

そもそも出来ないのか??とも思っているのですが、
もし、動的にカスタム属性を追加する方法をご存知でしたら、
教えて下さい。

お願いします。

環境
.net framework 2.0
vb.net
windows 7

テストコード

Public Class Form1

Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

Dim c As New TestClass

For Each attr As Object In c.GetType.GetCustomAttributes(False)
If TypeOf attr Is MyCustomAttribute Then
MsgBox(DirectCast(attr, MyCustomAttribute).MyValue)
End If
Next

'こんなのがあったらな…
'c.GetType.AddCustomAttributes(new MyCustomAttribute(SampleValue.A))

End Sub
End Class

Public Enum SampleValue
A
B
C
End Enum

Class MyCustomAttribute : Inherits System.Attribute

Public MyValue As SampleValue

Public Sub New(ByVal p As SampleValue)
MyValue = p
End Sub

End Class


<MyCustomAttribute(SampleValue.C)> _
Class TestClass

End Class

以上です。
よろしくお願いします。
リフレクションには、System.Reflection系とSystem.ComponentModel系があります。
// それぞれの正式な呼び方は知りませんが。前者がリフレクションで、後者が型記述子、ってことでいいのかな?

System.ComponentModel系はTypeDescriptorクラスを中心としていろいろな記述子を扱いますが、こちらであれば、TypeDescriptor.AddAttributesメソッドによって属性を追加し、追加した属性をTypeDescriptor.GetAttributesで取得できます。
この場合、型に対する追加・取得だけでなく特定インスタンスに対してのみの追加・取得も可能です。

System.Reflection系は、TypeクラスおよびSystem.Reflection内の各クラスによるものですが、こちらでの追加機構は私が知る限りは存在しません。
TypeDescriptor.AddAttributesしても、Type.GetCustomAttributesの結果には影響しません。
■No30498に返信(あゆさんの記事)

目的はなんでしょう?
それが分かれば他に良い方法があるかもしれません。
Hongliang さん
shu さん

ご回答ありがとうございます。

> Hongliang さん

System.ComponentModel.TypeDescriptorは初めて知りました。
実際にTypeDescriptor.AddAttributesを使用して、
テストコードではカスタム属性の追加することは出来たのですが、
最終的に私が目指していたものは出来ませんでした。

また、TypeDescriptorについて調べていたときに見つけたものですが、
http://msdn.microsoft.com/ja-jp/library/system.componentmodel.typedescriptor(v=vs.80).aspx
によると、
「リフレクションによって返される型に関する情報は、対象の型をコンパイルした後に変更できないという点で拡張性がありません。」
という事で、リフレクションでは出来ない事が判明しました。。。

> shu さん

今回、私が最終的にやりたかったことを具体的に書くと、
Oracle Databaseを使用したアプリを作ろうとしています。

そこで、odp.netを使用して、データアクセス回りを実装しているのですが、
Oracleユーザー定義タイプ(UDT)を使っているテーブルがありまして、
UDTにアクセスするには、
http://docs.oracle.com/cd/E16635_01/win.111/e06104/featUDTs.htm
によると、
1.OracleCustomTypeMappingAttributeを指定する
2.XML構成ファイルにカスタム・タイプ・マッピングの定義をする
のいづれかを行わないといけない事が分かりました。

ですが、いづれの場合でも、
1UDTに対して1つの定義を行わなくてはいけない(らしい?)ので、
UDTが100あったら、100のそれ用の定義をしなくてはいけませんし、
アプリ作成後にUDTが登録されたり更新された場合に、
アプリ側も、それに合わせて修正しないといけなくなるのが
煩わしいかな…と。

そこで、汎用的なクラスを作成し、
動的にカスタム属性を追加できるようになれば、
キレイに収まるかなぁ…と思い調査していました。

TypeDescriptor.AddAttributesを使って、
OracleCustomTypeMappingAttributeを追加しても、
odp.netではTypeDescriptorを参照していないらしく、
UDTにアクセスできませんでした。

イメージとすると、
「Visual Studio」+「Oracle Developer Tools for Visual Studio」では、
サーバーエクスプローラーからOracle Databaseに接続して、
UDTを使っているテーブルが普通に開けて、データが参照出来ているので、
そんな感じにアクセス出来たらいいかな…と思っています。

なにかアイデアがありましたら教えてください。
よろしくお願いします。
■No30501に返信(あゆさんの記事)

手元にOracle環境がないので確かなことは言えませんが
> 1UDTに対して1つの定義を行わなくてはいけない(らしい?)ので、
> UDTが100あったら、100のそれ用の定義をしなくてはいけませんし、
静的に型情報を持つならこれは避けられません。

動的に処理をするならUDTの情報を取得する方法と、UDTの値をByte配列などの
汎用的な型の変数に取得する方法が必要だと思います。
shuさん

あゆです。

返信ありがとうございます。

>>1UDTに対して1つの定義を行わなくてはいけない(らしい?)ので、
>>UDTが100あったら、100のそれ用の定義をしなくてはいけませんし、
> 静的に型情報を持つならこれは避けられません。

当初、リフレクションでカスタム属性を追加出来るかなぁ…
と考えていたので、複数のUDTを1つの定義で…と思っていたのですが、
Hongliangさんに教えていただいた、
TypeDescriptorについて調査している過程において、
リフレクションではカスタム属性を追加出来ないと判明したので、
shuさんの仰るとおり、100のUDTには100の定義が必要と思っています。

> 動的に処理をするならUDTの情報を取得する方法と、UDTの値をByte配列などの
> 汎用的な型の変数に取得する方法が必要だと思います。

UDTの情報を取得するのは可能なのですが、
アプリ側にUDTの静的な定義がないとNGという時点で、
動的にどうこうすること自体が難しいというより、
出来ないのでは…と諦めました。。。

残念な結果になりましたが、
Hongliangさん、shuさん
ありがとうございました!
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板