96

クラスで宣言されている順序で、リフレクションを使用してすべてのプロパティを取得する必要があります。MSDNによると、使用時に順序を保証することはできませんGetProperties()

GetProperties メソッドは、アルファベット順や宣言順など、特定の順序でプロパティを返しません。

しかし、プロパティをMetadataToken. だから私の質問は、それは安全ですか?それに関するMSDNに関する情報が見つからないようです。または、この問題を解決する他の方法はありますか?

私の現在の実装は次のようになります。

var props = typeof(T)
   .GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
   .OrderBy(x => x.MetadataToken);
4

10 に答える 10

171

.net 4.5 (および vs2012 の .net 4.0 でさえ) では、属性を使用した巧妙なトリックを使用して、リフレクションをより適切に実行できます。これにより[CallerLineNumber]、コンパイラーがプロパティに順序を挿入できるようになります。

[AttributeUsage(AttributeTargets.Property, Inherited = false, AllowMultiple = false)]
public sealed class OrderAttribute : Attribute
{
    private readonly int order_;
    public OrderAttribute([CallerLineNumber]int order = 0)
    {
        order_ = order;
    }

    public int Order { get { return order_; } }
}


public class Test
{
    //This sets order_ field to current line number
    [Order]
    public int Property2 { get; set; }

    //This sets order_ field to current line number
    [Order]
    public int Property1 { get; set; }
}

次に、リフレクションを使用します。

var properties = from property in typeof(Test).GetProperties()
                 where Attribute.IsDefined(property, typeof(OrderAttribute))
                 orderby ((OrderAttribute)property
                           .GetCustomAttributes(typeof(OrderAttribute), false)
                           .Single()).Order
                 select property;

foreach (var property in properties)
{
   //
}

部分クラスを処理する必要がある場合は、 を使用してプロパティをさらに並べ替えることができます[CallerFilePath]

于 2013-08-01T15:30:59.860 に答える
17

属性ルートを使用する場合は、私が過去に使用した方法を次に示します。

public static IOrderedEnumerable<PropertyInfo> GetSortedProperties<T>()
{
  return typeof(T)
    .GetProperties()
    .OrderBy(p => ((Order)p.GetCustomAttributes(typeof(Order), false)[0]).Order);
}

次に、このように使用します。

var test = new TestRecord { A = 1, B = 2, C = 3 };

foreach (var prop in GetSortedProperties<TestRecord>())
{
    Console.WriteLine(prop.GetValue(test, null));
}

どこ;

class TestRecord
{
    [Order(1)]
    public int A { get; set; }

    [Order(2)]
    public int B { get; set; }

    [Order(3)]
    public int C { get; set; }
}

すべてのプロパティで比較可能な属性を持たない型でメソッドを実行すると、メソッドは明らかに barf するため、使用方法に注意し、要件を満たす必要があります。

Order : Attribute の定義は省略しました。Yahia の Marc Gravell の投稿へのリンクに良いサンプルがあるためです。

于 2012-01-30T13:02:12.133 に答える
12

MSDN によると、MetadataTokenモジュールは 1 つのモジュール内で一意です。順序がまったく保証されているとは言えません。

希望どおりに動作したとしても、それは実装固有であり、予告なしにいつでも変更される可能性があります。

この古いMSDN ブログ エントリを参照してください。

このような実装の詳細への依存を避けることを強くお勧めします - Marc Gravell からのこの回答を参照してください。

コンパイル時に何かが必要な場合は、Roslynを調べることができます(ただし、非常に初期の段階にあります)。

于 2012-01-30T11:03:36.593 に答える
5

別の可能性は、System.ComponentModel.DataAnnotations.DisplayAttribute Orderプロパティを使用することです。組み込みであるため、新しい特定の属性を作成する必要はありません。

次に、このような順序付けられたプロパティを選択します

const int defaultOrder = 10000;
var properties = type.GetProperties().OrderBy(p => p.FirstAttribute<DisplayAttribute>()?.GetOrder() ?? defaultOrder).ToArray();

そして、クラスはこのように提示できます

public class Toto {
    [Display(Name = "Identifier", Order = 2)
    public int Id { get; set; }

    [Display(Name = "Description", Order = 1)
    public string Label {get; set; }
}
于 2020-01-21T15:42:31.047 に答える
4

MetadataToken による並べ替えをテストしたことは機能します。

ここにいるユーザーの何人かは、これはどういうわけか良いアプローチではない/信頼できないと主張していますが、私はまだその証拠を見たことがありません.

下位互換性について - 現在 .net 4 / .net 4.5 で作業している間 - Microsoft は .net 5 以降を作成しているため、この並べ替え方法が将来壊れることはほとんどないと想定できます。

もちろん、.net9 にアップグレードする 2017 年までには互換性の問題が発生する可能性がありますが、その時までに、Microsoft の担当者はおそらく「公式の並べ替えメカニズム」を理解するでしょう。戻ったり、壊したりしても意味がありません。

プロパティの順序付けのために追加の属性をいじるのにも時間と実装が必要です。

于 2015-03-09T20:18:57.787 に答える
0

追加の依存関係に満足している場合は、Marc Gravell のProtobuf-Netを使用して、リフレクションやキャッシュなどを実装するための最良の方法について心配することなく、これを行うことができます。次を使用してフィールドを装飾し、[ProtoMember]次を使用して番号順にフィールドにアクセスするだけです。

MetaType metaData = ProtoBuf.Meta.RuntimeTypeModel.Default[typeof(YourTypeName)];

metaData.GetFields();
于 2012-12-14T13:08:46.393 に答える