记录对象状态。将其所有属性值作为字符串获取。

8
public class Address
{
    public string AddressLine1 { get; set; }
    public string AddressLine2 { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    public string Zip { get; set; }
}
......
var emp1Address = new Address();
emp1Address.AddressLine1 = "Microsoft Corporation";
emp1Address.AddressLine2 = "One Microsoft Way";
emp1Address.City = "Redmond";
emp1Address.State = "WA";
emp1Address.Zip = "98052-6399";

考虑上述类及其初始化。现在在某个时刻,当发生错误时,我想记录其状态。我希望获得以下类似的字符串日志。
string toLog = Helper.GetLogFor(emp1Address);

toLog字符串应该长成以下这个样子。

AddressLine1 = "Microsoft Corporation";
AddressLine2 = "One Microsoft Way";
City = "Redmond";
State = "WA";
Zip = "98052-6399";

然后我将记录toLog字符串。

如何在Helper.GetLogFor()方法中访问对象的所有属性名称和属性值?

我实现的解决方案:

/// <summary>
/// Creates a string of all property value pair in the provided object instance
/// </summary>
/// <param name="objectToGetStateOf"></param>
/// <exception cref="ArgumentException"></exception>
/// <returns></returns>
public static string GetLogFor(object objectToGetStateOf)
{
  if (objectToGetStateOf == null)
  {
    const string PARAMETER_NAME = "objectToGetStateOf";
    throw new ArgumentException(string.Format("Parameter {0} cannot be null", PARAMETER_NAME), PARAMETER_NAME);
  }
  var builder = new StringBuilder();

  foreach (var property in objectToGetStateOf.GetType().GetProperties())
  {
    object value = property.GetValue(objectToGetStateOf, null);

        builder.Append(property.Name)
        .Append(" = ")
        .Append((value ?? "null"))
        .AppendLine();
  }
  return builder.ToString();
}

有没有不使用序列化的原因? - John Saunders
我希望以人类可读的格式来展示它,这样每当我需要查看日志时,我就可以快速地看到错误发生时对象中任何属性的值是什么。 - IsmailS
3个回答

25
public static string GetLogFor(object target)
{
    var properties =
        from property in target.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance)
        select new
        {
            Name = property.Name,
            Value = property.GetValue(target, null)
        };

    var builder = new StringBuilder();

    foreach(var property in properties)
    {
        builder
            .Append(property.Name)
            .Append(" = ")
            .Append(property.Value)
            .AppendLine();
    }

    return builder.ToString();
}

builder.Append(property.Name).Append(" = ").AppendLine(property.Value); 语句中编译错误:参数类型 'object' 无法分配给参数类型 'string'。 - IsmailS
你能帮我理解一下 .GetProperties(BindingFlags.Public | BindingFlags.Instance) 是什么意思吗? - IsmailS
@Ismail:我已经更新了我的代码,以消除那个错误。我从来没有注意到AppendLineAppend不具有相同的重载集。 - Bryan Watts
@Ismail:这行代码的意思是“获取所有公共属性,并且是实例属性(而不是静态属性)”。 - Bryan Watts
@Bryan!非常感谢你与我分享这一信息。 - IsmailS

5
static void Log(object @object)
{
    foreach (var property in @object.GetType().GetProperties())
        Console.WriteLine(property.Name + ": " + property.GetValue(@object, null).ToString());
}

调用ToString会导致空属性值引发NullReferenceException异常。 - Bryan Watts
在访问属性值之前,我必须进行空值检查。 - IsmailS
我更喜欢这个答案,因为它没有使用Linq。 - UpTheCreek

1

您可以使用反射来访问属性名称,如下所示

Type t = emp1Address.GetType();


PropertyInfo [] pi = t.GetProperties();
   foreach (PropertyInfo p in pi)
   {

     //You can get the value (using GetValue() method) and name (p.Name) here.



   }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接