Как получить доступ к публичным свойствам List<class> по их порядковому положению
У меня есть открытые свойства класса, и моя строка вывода выводится так:
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());
}
Есть ли способ, чтобы цикл foreach в OutputListToFile мог быть переписан так, чтобы я мог устранить эту зависимость упорядочения. Вот фрагмент класса 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; }
3 ответа
Я не уверен, что это то, что вы хотите, но если вы хотите записать содержимое всех свойств в том же порядке, в котором они находятся column
, вы можете просто использовать это:
foreach (var c in listData)
{
foreach (var column in columns)
{
md.Append(column.GetValue(c, null));
}
}
Этот код не использует разделитель и терминатор в качестве исходного кода, но я уверен, что вы легко можете это исправить.
Если вы рассмотрите возможность аннотирования свойств с помощью атрибута, это решение будет работать:
[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;
}
}
Если вы хотите получить значения свойств, вам нужно будет позвонить .Cast<PropertyInfo>()
на IEnumerable<MemberInfo>
вернулся GetOrderedMembers()
,
Рассмотрите возможность использования Dictionary<string, string>
для вашего DocMetaData (вместо класса), где первое - это имя поля, а второе - значение. Затем вы можете получить значения, используя массив столбцов.