6

hereに示すように、属性値を取得するために反映するまで、属性コンストラクターは呼び出されません。ただし、ご存知かもしれませんが、コンパイル時の定数値のみを属性コンストラクターに渡すことができます。どうしてこれなの?多くの人が次のようなことをすることを好むと思います:

[MyAttribute(new MyClass(foo, bar, baz, jQuery)]

これらの値で文字列を渡すよりも (文字列型のコードも引き起こします!)、文字列に変換し、実際の値を使用するだけでなく、コンパイル時の警告/エラーを使用する代わりに、Regex に依存して値を取得しようとします。呼び出されたメソッドが間違って入力されたいくつかの属性を使用することを除いて、クラスとは関係のない場所でスローされる可能性のある例外について。

これを引き起こした制限は何ですか?

4

4 に答える 4

12

属性はメタデータの一部です。そのアセンブリでコードを実行せずに、アセンブリのメタデータを反映できる必要があります。

たとえば、ソース コードをコンパイルするためにアセンブリから属性を読み取る必要があるコンパイラを作成しているとします。参照されたアセンブリ内のコードを読み込んで実行しますか? コンパイル中に参照されたアセンブリで任意のコードを実行できるコンパイラを作成することを、コンパイラ作成者に要求します? クラッシュしたり、無限ループに陥ったり、開発者が対話する権限を持たないデータベースに接続したりする可能性のあるコードはありますか? ひどいシナリオの数は膨大であり、属性を非常に単純にすることを要求することで、それらをすべて排除します。

于 2013-06-03T03:12:45.083 に答える
3

問題はコンストラクターの引数にあります。それらはどこかから来る必要があり、属性を消費するコードによって提供されません。それらは、コンストラクターを呼び出して属性オブジェクトを作成するときに、Reflection 配管によって提供される必要があります。コンストラクターの引数値が必要です。

これは、コンパイル時にコンパイラが属性を解析し、コンストラクタの引数を記録することから始まります。これらの引数値は、アセンブリ メタデータにバイナリ形式で格納されます。問題は、ランタイムがこれらの値を逆シリアル化するための高度に標準化された方法を必要とすることです。これは、通常、データを逆シリアル化/シリアル化するために使用する .NET クラスのいずれにも依存しないことが望ましいです。このようなクラスが実行時に実際に使用できるという保証はないため、Micro Framework のように非常にトリムされたバージョンの .NET にはなりません。

BinaryFormatter クラスを使用したバイナリ シリアライゼーションと同じくらい一般的なことでさえ面倒です。クラスで [Serializable] 属性を使用してジョブを実行できるようにする必要があることに注意してください。バージョン管理も大きな問題になります。古いアセンブリの属性を破壊するリスクがあるため、 そのようなシリアライザー クラスを変更することはできません。

これは、CLS の設計者が属性コンストラクターに許可される型を大幅に制限することで解決した、難しい問題です。単純な値の型、文字列、それらの単純な 1 次元配列、および Type だけを残しました。それらのバイナリ表現はシンプルで明確であるため、デシリアライズに問題はありません。かなりの制限がありますが、アトリビュートはかなり表現力豊かです。究極のフォールバックは、文字列を使用し、実行時にコンストラクターでその文字列をデコードすることです。MyClass のオブジェクトを作成することは問題ではありません。属性コンストラクターで作成できます。ただし、このコンストラクターが必要とする引数を属性のプロパティとしてエンコードする必要があります。

于 2013-06-02T13:49:16.617 に答える
-1

これを引き起こした制限は何ですか?

あなたが説明したことができない理由は、おそらく何らかの制限によるものではありませんが、それは純粋に言語設計上の決定です。基本的に、言語を設計するとき、彼らは「これは可能であるべきだが、これは不可能だ」と言った。彼らが本当にこれを可能にしたいのであれば、「制限」は対処されており、これは可能です. ただし、この決定の背後にある具体的な理由はわかりません。

/.../ これらの値を含む文字列を渡し (文字列型のコードも引き起こします!)、文字列に変換し、実際の値を使用するだけでなく、Regex に依存して値を取得しようとします /.../

私も似たような状況に陥ったことがあります。機能的な方法で何かを実装するために、ラムダ式で属性を使用したいことがありました。しかし、結局のところ、c# は関数型言語ではなく、非関数型の方法でコードを記述した場合、そのような属性は必要ありませんでした。

要するに、私は次のように考えています。これを関数的な方法で開発したい場合は、f# のような関数型言語を使用する必要があります。現在、私はc#を使用していますが、機能しない方法でそれを行っているため、そのような属性は必要ありません。

おそらく、現在のように属性を使用するのではなく、単純に設計を再検討する必要があります。

更新 1:

c# は関数型言語ではないと主張しましたが、それは主観的な見方であり、「関数型言語」の厳密な定義はありません。私は Adam Wright の意見に同意します。なぜ C#は関数型プログラミング言語なのですか?

更新 2: Jon Skeet によるこの投稿を見つけました: https://stackoverflow.com/a/294259/1105687ジェネリック属性タイプを許可しないことを考慮していますが、この場合の理由は似ている可能性があります。

Eric Lippert からの回答 (言い換え): 特に理由はありませんが、あまり価値のないユース ケースで言語とコンパイラの両方が複雑になるのを避けるためです。

于 2013-06-01T19:22:40.260 に答える