我想将属性名称和匹配数据写入分隔文件,我已经从c#objectdumper帮助文件中复制了一些代码,这一切似乎都运行正常,但我不理解反射足以自信使用它。我担心的是错误的列中存在不正确的值,是否可能发生这种情况,例如。
Field1,Field2
Val1,Val2
Val1,Val2
Val2,Val1 << Could this ever happen ?
这段代码又是什么意思?
f != null ? f.GetValue(this) : p.GetValue(this, null)
以下代码:
public string returnRec(bool header, string delim)
{
string returnString = "";
bool propWritten = false;
MemberInfo[] members = this.GetType().GetMembers(BindingFlags.Public | BindingFlags.Instance);
foreach (MemberInfo m in members)
{
FieldInfo f = m as FieldInfo;
PropertyInfo p = m as PropertyInfo;
if (f != null || p != null)
{
if (propWritten)
{
returnString += delim;
}
else
{
propWritten = true;
}
if (header)
returnString += m.Name;
else
{
Type t = f != null ? f.FieldType : p.PropertyType;
if (t.IsValueType || t == typeof(string))
{
returnString += f != null ? f.GetValue(this) : p.GetValue(this, null);
}
}
}
}
return returnString;
}
答案 0 :(得分:1)
输入t = f!= null? f.FieldType:p.PropertyType;
这是一个内联if,ask是f!= null然后f.FieldType else p.PropertyType
可以写成
Type t;
if (f != null)
t = f.FieldType;
else
t = p.PropertyType;
答案 1 :(得分:0)
@astander已经就Type t = f != null ? f.FieldType : p.PropertyType;
问题给了你答案,所以我会把那个问题留下来。关于将值放入正确的列,我不知道wheter反射保证以特定顺序列出类型的成员,但您可以通过在使用之前对列表进行排序来保证它(使用Linq):
MemberInfo[] members = typeof(Item).GetMembers(BindingFlags.Public | BindingFlags.Instance);
IEnumerable<MemberInfo> sortedMembers = members.OrderBy(m => m.Name);
foreach (MemberInfo member in sortedMembers)
{
// write info to file
}
或者,如果您更喜欢非Linq方法(适用于.NET Framework 2.0):
MemberInfo[] members = typeof(Item).GetMembers(BindingFlags.Public | BindingFlags.Instance);
Array.Sort(members, delegate(MemberInfo x, MemberInfo y){
return x.Name.CompareTo(y.Name);
});
foreach (MemberInfo member in members)
{
// write info to file
}
答案 2 :(得分:0)
@astander和@Frederik基本上回答了你明确提出的问题和疑虑,但我想建议以更有效的方式做事。根据您希望写入文件的对象实例的数量,您提供的方法可能最终效率很低。那是因为你通过每次迭代的反射来收集类型和价值信息,这是不必要的。
您要查找的内容是查找类型信息一次,然后仅使用反射来获取属性和字段的值,例如(.NET 3.5),
public static IEnumerable<string> ReturnRecs(IEnumerable items, bool returnHeader, string delimiter)
{
bool haveFoundMembers = false;
bool haveOutputHeader = false;
PropertyInfo[] properties = null;
FieldInfo[] fields = null;
foreach (var item in items)
{
if (!haveFoundMembers)
{
Type type = item.GetType();
properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.Where(pi => pi.PropertyType.IsValueType || pi.PropertyType == typeof (string)).ToArray();
fields = type.GetFields(BindingFlags.Public | BindingFlags.Instance)
.Where(fi => fi.FieldType.IsValueType || fi.FieldType == typeof(string)).ToArray();
haveFoundMembers = true;
}
if (!haveOutputHeader)
{
yield return String.Join(delimiter, properties.Select(pi => pi.Name)
.Concat(fields.Select(pi => pi.Name)).ToArray());
haveOutputHeader = true;
}
yield return String.Join(delimiter,
properties.Select(pi => pi.GetValue(item, null).ToString())
.Concat(fields.Select(fi => fi.GetValue(item).ToString())).ToArray());
}
上述代码每个记录组只执行一次GetProperties
和GetFields
- 因此,无需对属性进行显式排序和弗雷德里克的建议一样。
答案 3 :(得分:0)
只是为接受的答案添加一些想法,特别是对于大数据量:
PropertyInfo
等可能会不必要地缓慢;有办法避免这种情况,例如使用HyperDescriptor或其他动态代码TextWriter
作为采用这些方法的调整版本,请参见下文;请注意,我没有在此示例中启用HyperDescriptor,但这只是:
HyperTypeDescriptionProvider.Add(typeof(YourType));
总之...
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
static class Program {
static void Main() { // just some test data...
var data = new[] { new { Foo = "abc", Bar = 123 }, new { Foo = "def", Bar = 456 } };
Write(data, Console.Out, true, "|");
}
public static void Write<T>(IEnumerable<T> items, TextWriter output, bool writeHeaders, string delimiter) {
PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(typeof(T));
foreach (T item in items) {
bool firstCol = true;
if (writeHeaders) {
foreach (PropertyDescriptor prop in properties) {
if (firstCol) {
firstCol = false;
} else {
output.Write(delimiter);
}
output.Write(prop.Name);
}
output.WriteLine();
writeHeaders = false;
firstCol = true;
}
foreach (PropertyDescriptor prop in properties) {
if (firstCol) {
firstCol = false;
} else {
output.Write(delimiter);
}
output.Write(prop.Converter.ConvertToString(prop.GetValue(item)));
}
output.WriteLine();
}
}
}