公共属性及其值的列表

时间:2014-01-22 17:29:37

标签: c# reflection

.Net 4.5 C#

为了支持许多类的“导出到Excel”功能,我需要能够获取一个类,然后从中获取公共属性名称(对于标题)和属性值(对于行)的列表)

有没有办法反映一个类的实例并获取属性名称和属性值?

3 个答案:

答案 0 :(得分:1)

以下是有关如何执行此操作的快速示例。当然,您需要更新它才能正确创建/构建CSV,但这可以让您了解如何获得所需的值。

class Program
{
    static void Main(string[] args)
    {
        var myClass = new MyClass()
        {
            Number = 1,
            String = "test"
        };

        var properties = myClass.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);

        foreach (var property in properties)
        {
            var columnName = property.Name;
            var value = myClass.GetType().GetProperty(columnName).GetValue(myClass, null);

            Console.WriteLine(string.Format("{0} - {1}", columnName, value));
        }
        Console.ReadKey();
    }
}

public class MyClass
{
    public int Number { get; set; }
    public string String { get; set; }
}

答案 1 :(得分:1)

我实际上最近为我的工作创造了这样的东西。我正在编写一个自定义CSV序列化程序类来支持错误构思的CSV文件规范。

public CSVSerializer Serialize<T>(T data, Func<T, object> map)
{
    if (map == null) throw new ArgumentNullException("map");

    object mappedData = map(data);
    if (mappedData == null) throw new NullReferenceException("Mapped data produced null value");

    // Iterate over public members of `mappedData`
    MemberInfo[] members = mappedData.GetType().GetMembers(BindingFlags.Instance | BindingFlags.Public);
    List<string> values = new List<string>();
    foreach (MemberInfo member in members)
    {
        // Skip events and methods
        if (!(member is FieldInfo || member is PropertyInfo)) continue;

        // Value of `mappedData`
        object memberVal = MemberInfoValue(member, mappedData);
        if (memberVal == null)
        {
            // If the actual value stored by `memberVal` is null, store string.Empty and continue
            values.Add(string.Empty);
            continue;
        }

        // Check if `memberVal` contains a member named "map"
        MemberInfo[] maps = memberVal.GetType().GetMember("map");
        MemberInfo memberMap = maps.Length > 0 ? maps[0] : null;
        string val = MapToString(memberVal, o => o.ToString());

        if (map != null) // map is present
        {
            // Get first property other than map
            MemberInfo dataVal = memberVal.GetType().GetMembers(BindingFlags.Instance | BindingFlags.Public)
                                                .Where(mi => mi is FieldInfo || mi is PropertyInfo)
                                                .Except(new MemberInfo[] { memberMap })
                                                .DefaultIfEmpty(memberMap)
                                                .FirstOrDefault();

            object tmp = MemberInfoValue(memberMap, memberVal);
            if (dataVal == memberMap)
            {
                // map is only property, so serialize it
                val = MapToString(tmp, o => o.ToString());
            }
            else
            {
                // try to serialize map(dataVal), or use empty string if it fails
                Delegate dlg = tmp as Delegate;
                if (dlg != null)
                {
                    object param = MemberInfoValue(dataVal, memberVal);
                    try { val = MapToString(dlg, d => d.DynamicInvoke(param).ToString()); }
                    catch (Exception ex)
                    {
                        // exception should only occur with parameter count/type mismatch
                        throw new SerializationException(string.Format("Poorly formatted map function in {0}", member.Name), ex);
                    }
                }
                else
                {
                    // map is not a delegate (!!)
                    throw new SerializationException(string.Format("map member in {0} is not a delegate type", member.Name));
                }
            }
        }

        // Handle quotes and the separator string
        val = val.Trim('"');
        if (val.Contains("\""))
        {
            val = val.Replace("\"", "\\\"");
        }
        if (val.Contains(Separator))
        {
            val = string.Format("\"{0}\"", val);
        }

        values.Add(val);
    }
    string line = string.Join(Separator, values);
    Writer.WriteLine(line);

    return this;
}

此函数按照定义的顺序序列化data的公共字段和属性;这些成员的名字被忽略了。

如果您只对属性感兴趣,可以使用GetProperties代替GetMembers(使用PropertyInfo代替MemberInfo)。如果您没有创建CSV,则显然可以忽略CSV文件格式化部分。

MemberInfoValue(info, parent)会视情况退回((FieldInfo)info).GetValue(parent)((PropertyInfo)info).GetValue(parent, null)MapToString只是一个空值保护功能。

map参数的存在以及对名为“map”的成员的搜索是我特定情况的必要条件的一部分,尽管它可能对您有用。映射允许以下内容:

mySerializer.Serialize(myPersonObject,
    p => new {
        name = string.Format("{0}, {1}", p.LastName, p.FirstName),
        address = p.address
    });

我有Serialize的重载,调用Serialize(data, d => d);。寻找“地图”成员允许这样的事情:

mySerializer.Serialize(new {
        employeeID = new { val = myEmployeeObject.ID, map = d => d.ToUpperCase() },
        employeeName = myEmployeeObject.Name
    });

答案 2 :(得分:0)

您可以使用以下内容:

public static Dictionary<string, object> KeyValue(object obj)
{
    return obj.GetType().GetProperties().ToDictionary(
        m => m.Name, 
        m => m.GetValue(obj, new object[] { })
    );
}