公共属性列表及其值[重复]

Posted

技术标签:

【中文标题】公共属性列表及其值[重复]【英文标题】:List of public Properties and their values [duplicate] 【发布时间】:2014-02-12 22:00:49 【问题描述】:

.Net 4.5 C#

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

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

【问题讨论】:

【参考方案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 =&gt; d);。寻找“地图”成员允许这样的事情:

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

【讨论】:

【参考方案2】:

你可以这样使用:

public static Dictionary<string, object> KeyValue(object obj)

    return obj.GetType().GetProperties().ToDictionary(
        m => m.Name, 
        m => m.GetValue(obj, new object[]  )
    );

【讨论】:

【参考方案3】:

这里有一个关于如何做到这一点的快速示例。当然,您需要对其进行更新,以便正确创建/构造 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; 

【讨论】:

以上是关于公共属性列表及其值[重复]的主要内容,如果未能解决你的问题,请参考以下文章

按属性值对对象列表进行排序[重复]

如何在Python中的for循环内创建对象列表而不继承属性值[重复]

公共访问器与类的公共属性[重复]

最终静态变量及其使用[重复]

属性与公共成员变量[重复]

类中的属性与公共声明变量[重复]