2011-08-08 1 views
0

によってリスト のパブリックプロパティにアクセスするには、次のように書かれている: はどのように私は公共のクラスのプロパティと私の出力の詳細ラインを持っている彼らの順序位置

public static long OutputListToFile(StreamWriter writer, List<DocMetaData> listData) 
    { 
     StringBuilder md = new StringBuilder(); 
     int rowcount = 0; 
     foreach (var c in listData) 
     { 
      md.Append(c.Section); md.Append(DocMetaData.SEPARATOR); 
      md.Append(c.DocClass); md.Append(DocMetaData.SEPARATOR); 
      md.Append(c.Meeting); md.Append(DocMetaData.SEPARATOR); 
      md.Append(c.Agency); md.Append(DocMetaData.SEPARATOR); 
      md.Append(c.Country); md.Append(DocMetaData.SEPARATOR); 
      md.Append(c.Comment); md.Append(DocMetaData.SEPARATOR); 
      md.Append(c.Title); md.Append(DocMetaData.SEPARATOR); 
      md.Append(c.Folder); md.Append(DocMetaData.SEPARATOR); 
      md.Append(c.File); md.Append(DocMetaData.CARRIAGE_RETURN); 
      try 
      { 
       writer.WriteLine(md.ToString()); 
       rowcount++; 
      } 
      catch (Exception ex) 
      { 
       log.Fatal("Error in OutputListToFile:\r\n", ex); 
      } 
     } 
     return rowcount; 
    } 

md.Append文は、現在でなければなりません

private void OutputColumnNamesAsFirstLine(StreamWriter writer) 
    { 
     StringBuilder md = new StringBuilder(); 
     PropertyInfo[] columns; 
     columns = typeof(DocMetaData).GetProperties(BindingFlags.Public | 
                 BindingFlags.Instance); 
     int i = 0; 
     foreach (var columnName in columns) 
     { 
      i++; 
      md.Append(columnName.Name); md.Append(DocMetaData.SEPARATOR); 
     } 
     writer.WriteLine(md.ToString()); 
    } 

はOutputListToFileでforeachループは、私はこの順序依存性を排除することができるように書き直すことができな方法があります:非常に最初の行を書き込みルーチンと一致するように上記の正確な順序で配置。ここでDocMetaDataクラスの抜粋です:

public class DocMetaData 
{ 
    public const string SEPARATOR = "\t";  // horizontal tab is delimiter 
    public const string CARRIAGE_RETURN = "\r"; 

    public string Section { get; set; } 
    public string DocClass { get; set; } 
    public string Meeting { get; set; } 
    public string Agency { get; set; } 
    public string Country { get; set; } 
    public string Comment { get; set; } 
    public string Title { get; set; } 
    public string Folder { get; set; } 
    public string File { get; set; } 
+2

ランタイムは、 'Type.GetProperties()'の結果を順序付けるのに**必須ではなく、実際には呼び出し間で**結果を並べ替えるかもしれないことに注意してください。だから、この実装は実際には欠陥があります!それが動作し続けるということは、あなたが呼び出す定義されていない振る舞いの1つの可能な結果にすぎません。たとえば、ランタイムの新しいリリースでは、コードが簡単に壊れる可能性があります。 'GetProperties()'呼び出しの結果に少なくともあなた自身の命令を課すべきです。 'OutputListToFile()'メソッドは、この同じ順序に従うべきです。 – cdhowie

答えて

1

私は、これはあなたが望むものであるわからないんだけど、あなたは彼らがcolumnにいるのと同じ順序ですべてのプロパティの内容を書きたいならば、あなたはちょうどそれを使用することができます。

foreach (var c in listData) 
{ 
    foreach (var column in columns) 
    { 
     md.Append(column.GetValue(c, null)); 
    } 
} 

このコードセパレータとターミネータを元のコードとして使用しませんが、簡単に修正できます。

+0

ありがとうございます。私は他のルーチンからの列の "発見"をコピーしました:PropertyInfo [] columns; columns = typeof(DocMetaData).GetProperties(BindingFlags.Public | BindingFlags.Instance);あなたの内側のループは素晴らしい作品です! –

+0

@cdhowieがコメントで指摘したように、このようにすると現在動作していますが、必ずしもそうとは限りません。あなたは一度列のリストを取得し、2つの方法の間でそれを共有する必要があります。 – svick

1

は、最初のフィールド名、2番目の値である(代わりにクラスの)あなたのDocMetaDataためDictionary<string, string>を使用することを検討してください。次に、列配列を使用して値を取得できます。

2

あなたが属性を持つプロパティに注釈を検討する場合は、このソリューションが動作します:

[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false, Inherited = true)] 
public class OrdinalPositionAttribute : Attribute 
{ 
    public int Position { get; private set; } 

    public OrdinalPositionAttribute(int position) 
    { 
     Position = position; 
    } 
} 

public class DocMetaData 
{ 
    public const string SEPARATOR = "\t";  // horizontal tab is delimiter 
    public const string CARRIAGE_RETURN = "\r"; 

    [OrdinalPosition(0)] 
    public string Section { get; set; } 
    [OrdinalPosition(1)] 
    public string DocClass { get; set; } 
    [OrdinalPosition(2)] 
    public string Meeting { get; set; } 
    [OrdinalPosition(3)] 
    public string Agency { get; set; } 
    [OrdinalPosition(4)] 
    public string Country { get; set; } 
    [OrdinalPosition(5)] 
    public string Comment { get; set; } 
    [OrdinalPosition(6)] 
    public string Title { get; set; } 
    [OrdinalPosition(7)] 
    public string Folder { get; set; } 
    [OrdinalPosition(8)] 
    public string File { get; set; } 

    private void OutputColumnNamesAsFirstLine(StreamWriter writer) 
    { 
     StringBuilder md = new StringBuilder(); 
     var columns = Utility.GetOrderedMembers(typeof(DocMetaData)); 

     int i = 0; 
     foreach (var columnName in columns) 
     { 
      i++; 
      md.Append(columnName.Name); md.Append(DocMetaData.SEPARATOR); 
     } 
     writer.WriteLine(md.ToString()); 
    } 
} 

public static class Utility 
{ 
    public static IEnumerable<MemberInfo> GetOrderedMembers(Type type) 
    { 
     if (type == null) 
      throw new ArgumentNullException("type"); 

     return CreateGetOrderedMembersEnumerable(type); 
    } 

    private static IEnumerable<MemberInfo> CreateGetOrderedMembersEnumerable(Type type) 
    { 
     return from member in type.GetMembers(BindingFlags.Public | BindingFlags.Instance) 

       let ordinal = member.GetCustomAttributes(typeof(OrdinalPositionAttribute), true) 
            .OfType<OrdinalPositionAttribute>().FirstOrDefault() 

       where ordinal != null 

       orderby ordinal.Position ascending 

       select member; 
    } 
} 

あなたがプロパティの値を取得したい場合、あなたはGetOrderedMembers()によって返さIEnumerable<MemberInfo>.Cast<PropertyInfo>()を呼び出す必要があります。

+0

うわー!私はちょうどそのテクニックの脆弱性に関するオリジナルのポスト警告の下であなたのコメントを読んでいます。よりエレガントで堅牢な提案ソリューションを投稿していただきありがとうございます。私は今吸収するのが大変ですが、私は明日これを再訪します。あなたの時間と注意していただきありがとうございます。 –

+0

問題ありません。私の解決策は一種のもので、一緒に投げ込まれたことに注意してください。クラスでこのようなことをたくさんしているのであれば、あなたのニーズに合った標準的な方法で解決するかもしれません。 – cdhowie

関連する問題