GetCustomAttributes()は、.NETでの属性の順序を保持していますか?
-
20-08-2019 - |
質問
タイトルはかなりそれをすべて言います。私は私のクラスを介して、いくつかの反射をやっているときは、MemberInfo.GetCustomAttributes()メソッドは、メンバーの属性の順序を維持、あるいはしないのだろうか?公式ドキュメントは何も一つの方法または他を言っていません。
<時間>私はこれを必要とするなぜあなたは迷っている場合は、ここでの完全な説明があります。それが今で提起されていますが、おそらく誰かが属性列挙順に頼る必要としない大きな問題に対する別の解決策を考え出すことができるよう、それは長いと質問のために必要ではありません。
私はかなり長い寿命を持つことが期待されている(ASP.NET)アプリケーションのための柔軟なフレームワークを作成しようとしています。コースでは、メニューからアクセスできるようにする必要があります多くの形態を得ることができます。開発者が来るのを人生を容易にするために、私はあなたがフォームのクラスに適用することができMenuItemAttribute
を作りました。この属性は、正確フォームがメニューに常駐する場所を開発者が指定することができ、そのコンストラクタで文字列パラメータの無制限の量を持っています。これはオープン、その後だろう - 典型的な使用例では、メニューには「受注」の項目があるだろう、その下の項目「クライアント」が存在することになるその下の項目「会社」を持つべきであることを意味する[MenuItem("Company", "Clients", "Orders")]
ようなものになるだろうフォーム。必要に応じて、単一のフォームは、これらの属性のいくつかを持つことができます - それは、メニュー内の複数の場所からacessibleになります。
もちろん、全体のメニューは私のアセンブリ内のすべてのクラスを列挙して、この属性を検索することによって、実行時に構築されています。しかし、最近私は、メニュー項目が事前に定義された方法でソートされなければならない要求を得ています。機能が関連しているフォームは、メニューで隣同士にする必要があります。これは、NOTアルファベット順のソートが、開発者が指定することを事前に定義されたためであることに注意してください。
これは、問題をもたらします - どのように私はこれらの属性の順序を指定するのですか?一つはMenuItemOrderHintAttribute
階層全体を説明するので、注文仕様は、階層の順序全体の数値(又は少なくとも一部)をも含むべきです。階層だけ下位レベルの注文数が十分でない。
私は別の属性を作ることができます。したがって、元の質問ます。
私はまた、拡張することができ<=>二つの配列またはペアの配列のいずれかを取るために、それは、その後の構文をたくさん複雑になります。最後のアイデアは、私は文字列が特別なフォーマットを持って作ることができるということですが、それはかなり厄介な私見になります。
<時間>OK、私は別の考えを持っています。のは、ジョンスキートが提案順序を使用してみましょう。これは、階層の最後のレベル、高くないもののために順序を指定することができます。それはクラスにするだけでなく、アセンブリ自体にだけではなく、適用されるようにしかし、私は属性を変更することができます。この場合、メニュー項目は関連するフォームを持っていないでしょう。アセンブリレベルでは、これらの属性は、階層のより高いレベル間の順序を指定するために使用することができます。
これは、その後、集中と分散型のメニューシステムとの間のトレードオフです。任意の考えは、なぜこれが悪い考えでしょうか?
解決
私は「注文」または「優先」であるMenuItemAttributeコンストラクタ、単一の余分な(オプション)値を入れたいです
[MenuItem(0, "Company", "Clients", "Orders")]
[MenuItem(1, "Foo", "Bar", "Baz")]
私はそれはかなりだろう言っていないんだけど、それが効果的にあなたが順序を指定することができるようになります。
他のヒント
ファイル内の要素の字句順序があるの絶対の結果CILアセンブリにとにかく永続化するも、リフレクションから返された結果で尊重される保証はありません。この順序は同じであってもアプリケーションドメイン内の同じにわたり繰り返し呼び出しであることが保証されていません!
それは現時点で動作するように起こっていても何もないので、(彼らはそれをしなかったとして、これは実際に自分のコードの一部についていくつかの問題を引き起こしていることに留意)MSは、過去に反射の他の部分で、この順序付けが壊れていることに注意してください将来的には、異なるプラットフォーム上で、この破壊を停止します。
の順序に依存するよりも、直接ではなく、意味情報を表現できるように、あなたの属性モデルの変更を検討します。
残念ながらありません、あなたは順序はあなたがそれらを指定された順序と同じであることを保証することはできません。
編集:回避策
免責事項:私はあなたの究極の問題を誤解していた場合、私は事前に謝罪。
。それはあなたがn
と持ってMenuItemAttribute
属性のコンストラクタで、開発者が入力したこれらの文字列の順序を維持するために渡すことLinkedList<String>
文字列の数をできるようにする必要があるかのように聞こえます。
ここでは可能な解決策はあります:
維持するために params String[]
に使用<=>持っていますその状態。次に、あなたのコンストラクタで<=>を反復し、秩序を維持する<=>に追加することもできます。
あなたの問題は、本当に彼らはあなたがアセンブリ内のすべてのフォームを組み合わせることで、メニューを構築しようとしていることを意味し、あなたのメニューに表示される場所のフォームが指定されているという事実から生じるように私には思えます。あなたが任意のフォームとは別に、メニューの構造を指定して、メニュー項目に対応するクラスで定義された様々なpropeties /属性からフォームを解決する場合、それは簡単になります。
例えばます。
public class MenuItem
{
string Text { get; }
Type FormType { get; }
ICollection<MenuItem> SubItems { get; }
}
メニュー項目が選択されたときに次に、何とか形を解決し、それを表示します。このアプローチは、新しいフォームがフォーム自体と一緒にメニュー構造を指定するコードを変更する必要が必要という欠点があるが、それは非常に軽微であります...