16

タイトルはほとんどそれをすべて言います。クラスを介していくつかのリフレクションを行っている場合、MemberInfo.GetCustomAttributes() メソッドはメンバーの属性の順序を保持しますか? 公式ドキュメントには、いずれにしても何も書かれていません。


なぜこれが必要なのか疑問に思っている場合は、ここに完全な説明があります。それは長く、現在提起されている質問には必要ありませんが、属性の列挙順序に依存しない、より大きな問題に対する代替の解決策を誰かが考え出すことができるかもしれません。

かなり長い寿命が期待される (ASP.NET) アプリケーション用の柔軟なフレームワークを作成しようとしています。コースの過程で、メニューからアクセスできる必要がある多くのフォームが得られます。開発者の負担を軽減MenuItemAttributeするために、フォームのクラスに適用できる を作成しました。この属性のコンストラクターには無制限の量の文字列パラメーターがあり、開発者はフォームがメニュー内のどこに存在するかを正確に指定できます。典型的な使用例は次のようになります[MenuItem("Company", "Clients", "Orders")]これは、メニューに「会社」という項目があり、その下に「クライアント」という項目があり、その下に「注文」という項目があり、フォームが開くことを意味します。必要に応じて、単一のフォームにこれらの属性をいくつか含めることができます。これにより、メニューのいくつかの場所からアクセスできるようになります。

明らかに、アセンブリ内のすべてのクラスを列挙し、この属性を検索することにより、メニュー全体が実行時に構築されます。しかし最近、メニュー項目を事前定義された方法でソートする必要があるというリクエストを受け取りました。関連する機能を持つフォームは、メニュー内で隣り合わせにする必要があります。これはアルファベット順ではなく、開発者が指定した定義済みの順序であることに注意してください。

これにより問題が発生します。これらの属性で順序を指定するにはどうすればよいですか? 階層全体を記述するためMenuItemAttribute、注文仕様には階層全体 (または少なくとも一部) の注文番号も含める必要があります。階層の下位レベルの注文番号だけでは十分ではありません。

別の属性 - を作成することもできますMenuItemOrderHintAttributeが、複数ある場合に問題が発生しMenuItemAttributeます。したがって、元の質問。

MenuItemAttribute2 つの配列またはペアの配列のいずれかを取るように を拡張することもできますが、それでは構文が非常に複雑になります。最後のアイデアは、文字列に特別な形式を持たせることができるということですが、それはかなり面倒です。


わかりました、別のアイデアがあります。Jon Skeet が提案した順序を使用しましょう。これにより、階層の上位レベルではなく、最終レベルの順序を指定できます。しかし、クラスだけでなく、アセンブリ自体にも適用されるように、属性を変更できます。この場合、メニュー項目にはフォームが関連付けられていません。アセンブリ レベルでは、これらの属性を使用して、階層の上位レベル間の順序を指定できます。

これは、集中型メニュー システムと分散型メニュー システムの間のトレードオフです。なぜこれが悪い考えになるのでしょうか?

4

4 に答える 4

18

ファイル内の要素の字句順序は、結果の CIL アセンブリで永続化されることも、Reflection から返される結果で尊重されることも絶対に保証されません。この順序は、同じアプリ ドメイン内で繰り返し呼び出された場合でも同じであるとは限りません。

MS は過去にリフレクションの他の部分でこの順序を破ったことに注意してください (彼らが行ったように、これが実際に一部のコードで問題を引き起こしたことに注意してください)。将来または別のプラットフォームで。

属性モデルを変更して、順序付けに依存するのではなく、セマンティック情報を直接表現できるようにすることを検討してください。

于 2009-01-26T15:08:42.393 に答える
8

「順序」または「優先順位」である、MenuItemAttribute コンストラクターに 1 つの追加 (オプション) の値を入れます。

[MenuItem(0, "Company", "Clients", "Orders")]
[MenuItem(1, "Foo", "Bar", "Baz")]

きれいだと言っているわけではありませんが、効果的に順序を指定できるようになります。

于 2009-01-26T14:56:49.297 に答える
1

残念ながら、指定した順序と同じ順序になることは保証できません。

編集:回避策

免責事項:あなたの最終的な問題を誤解している場合は、事前にお詫び申し上げます。

n開発者が属性コンストラクターに入力した文字列の数を渡して、これらの文字列の順序MenuItemAttributeMenuItemAttribute維持できるようにする必要があるように思えます。

考えられる解決策は次のとおりです。

その状態を維持するためにMenuItemAttributea を使用してください。LinkedList<String>次に、コンストラクターで を反復処理し、順序を維持するparams String[]に追加できます。LinkedList<String>

于 2009-01-26T14:50:31.633 に答える
0

あなたの問題は、フォームがメニューのどこに表示されるかを指定しているという事実に本当に起因しているように思われます。つまり、アセンブリ内のすべてのフォームを組み合わせてメニューを作成しようとしているということです。メニューの構造をフォームとは別に指定し、メニュー項目に対応するクラスで定義されたさまざまなプロパティ/属性からフォームを解決すると、より簡単になる場合があります。

例えば

public class MenuItem
{
    string Text { get; }
    Type FormType { get; }
    ICollection<MenuItem> SubItems { get; }
}

次に、メニュー項目を選択したら、なんとかしてフォームを解決して表示します。このアプローチには、新しいフォームでは、フォーム自体とともにメニュー構造を指定するコードを変更する必要があるという欠点がありますが、それは非常にマイナーです...

于 2009-01-26T15:19:56.177 に答える