使用反射将类保存到delim文件

时间:2009-08-01 07:53:13

标签: c# reflection

我想将属性名称和匹配数据写入分隔文件,我已经从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;
}

4 个答案:

答案 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());
    }

上述代码每个记录组只执行一次GetPropertiesGetFields - 因此,无需对属性进行显式排序和弗雷德里克的建议一样。

答案 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();
        }
    }
}