0

System.Attributeクラスを使用することは(一見)良い考えであるように思われる状況に陥りました。

アプリケーションで印刷するオブジェクトがあり、各プロパティの前にラベル(またはその前の文字列)が必要です。各プロパティを次のようにハードコーディングできます。

Console.WriteLine("Color:"+obj.color);
Console.WriteLine("Size:"+obj.size);

各プロパティについても同様です。しかし、その代わりに、この「ラベル」をハードコーディングする必要がないコードを作成しようとしていたので、すべてのプロパティを動的に出力できました。

System.Attributeクラスを使用して、そのようなものを取得しました。

public class MyObject 
{
    [MyCustomLabel("Color:")]
    public string Color;

    [MyCustomLabel("Size:")]
    public string Size;
    //etc...
}

したがって、ここに私の問題があります。この属性の値を取得することは不可能ではありませんが、リフレクションを使用する必要があったため、フレンドリーではありません。

リフレクションを使用することはそれほど怖くありませんが、作成されていないものに属性を使用しているように見えました。

属性を使用するのに最適な場所はどこか、そしてこれが本当にそれを使用するための状況であるかどうか疑問に思います。

4

5 に答える 5

4

属性とリフレクションは密接に関連しています。一部のコンパイラ/ランタイム属性を除いて、コードを反映せずにそれらを使用する方法はありません。

System.ComponentModelとは言うものの、あなたのアプローチは合理的であり、有用なメタデータでプロパティを装飾するためのいくつかのクラスを持つ名前空間の属性を調べたいと思うかもしれません。

于 2009-06-30T03:50:35.040 に答える
1

あなたは正しい方向に進んでいます。

また、この目的のためにすでにカスタマイズされた[DisplayName]属性があります。これは、2.0以降.NETにあります。

http://msdn.microsoft.com/en-us/library/system.componentmodel.displaynameattribute.aspx

于 2009-06-30T04:21:39.310 に答える
1

コンソールに書き込んでいる場合、つまりデバッグスタイルの出力である場合、必要なのはタイプミス/コピー貼り付けエラーの可能性を最小限に抑えることです。

これは内部的には混乱を招きますが、コールサイトでは非常に効果的です。

public static void WriteNameAndValue<T,TValue>(
    this TextWriter tw, T t,
    Expression<Func<T, TValue>> getter)
{
    var memberExpression = getter.Body as MemberExpression;
    if (memberExpression == null)
        throw new ArgumentException("missing body!");
    var member = memberExpression.Member;
    tw.Write(member.Name);
    tw.Write(": ");
    if (member is FieldInfo)
    {
        tw.Write(((FieldInfo)member).GetValue(t));
    }
    else if (member is PropertyInfo)
    {
        tw.Write(((PropertyInfo)member).GetValue(t, null));
    }
}


public static void WriteNameAndValueLine<T,TValue>(
    this TextWriter tw, T t,
    Expression<Func<T, TValue>> getter)
{

    WriteNameAndValue<T,TValue>(tw, t, getter);
    tw.WriteLine();
}

その後、あなたは書くことができます

t.Foo = "bar";
t.Bar = 32.5;
Console.Out.WriteNameAndValueLine(t, x => x.Foo);
Console.Out.WriteNameAndValueLine(t, x => x.Bar);
// output
// Foo: bar
// Bar: 32.5

これを実行時にリソースを介してより構成可能にし、ローカリゼーションを考慮して構成できるようにしたい場合は、そうすることができますが、これが必要と思われる場合は、代わりに別のより標準化されたアプローチを検討します。

PS派手になりたい場合は、FieldInfo/PropertyInfoスイッチを次のように置き換えることができます。

tw.Write(getter.Compile()(t));

次に、式でMethodInfoをチェックすることもできます(または任意のラムダを許可し、行番号またはその他の一般的なテキストを挿入するだけです。このルートをたどらないことをお勧めします。使用法はすでに混乱しています。これにより、不要な負荷が発生する可能性があります。単純なロギング方法である必要があります。

于 2009-06-30T11:43:33.183 に答える
0

これはまさにシリアル化の仕組みなので、あなたのアプローチは合理的だと思います。これにアプローチするもう1つの方法は、PropertyNamesとそのタイトルの辞書を作成し、プロパティ名に基づいてタイトルを検索することです。

于 2009-06-30T04:18:49.620 に答える
0

アプリケーションで印刷するオブジェクトがあり、各プロパティの前にラベル(またはその前の文字列)が必要です。

なぜあなたはあなたのケースで属性を使うことを考えますか?このオブジェクトをアプリケーションのどこに印刷しますか。

たぶん、オブジェクトにToString
を 実装するだけです。

public override string ToString()
{
    StringBuilder sb = new StringBuilder();

    sb.Append("PropertyX: ");
    sb.AppendLine(this.PropertyX);

    // get string from resource file
    sb.Append(Resources.FileName);
    sb.Append(": ");
    sb.AppendLine(this.FileName);

    sb.Append("Number: ");
    sb.AppendLine(this.Number.ToString());

    return sb.ToString();
}
于 2009-06-30T10:57:45.023 に答える