2012-03-14 57 views
0

以下函数需要查看输入对象的内部,如果它有一个属性,它返回一个自定义对象,它也需要修剪该对象。下面的代码适用于输入对象,但不会递归查看返回自定义对象并执行修剪过程的属性。作出函数递归

public object TrimObjectValues(object instance) 
{ 
    var props = instance.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public) 
       // Ignore non-string properties 
       .Where(prop => prop.PropertyType == typeof(string) | prop.PropertyType == typeof(object)) 
       // Ignore indexers 
       .Where(prop => prop.GetIndexParameters().Length == 0) 
       // Must be both readable and writable 
       .Where(prop => prop.CanWrite && prop.CanRead); 

    foreach (PropertyInfo prop in props) 
    { 
     if (prop.PropertyType == typeof(string)) 
     { 
      string value = (string)prop.GetValue(instance, null); 
      if (value != null) 
      { 
       value = value.Trim(); 
       prop.SetValue(instance, value, null); 
      } 
     } 
     else if (prop.PropertyType == typeof(object)) 
     { 
      TrimObjectValues(prop); 
     } 
    } 

    return instance; 
} 

我需要以某种方式改变这种寻找其他对象的初始对象内部

.Where(prop => prop.PropertyType == typeof(string) | prop.PropertyType == typeof(object)) 

此代码是不工作的原因是一个例子,对象我传递作为输入具有返回一个“Address”类型的属性,因此typeof(object)永远不会被命中。

下面是数据再次进行测试树传递给函数“O”在这种情况下

 Order o = new Order(); 

    o.OrderUniqueIdentifier = "TYBDEU83e4e4Ywow"; 

    o.VendorName = "Kwhatever"; 
    o.SoldToCustomerID = "Abc98971"; 
    o.OrderType = OrderType.OnOrBefore; 
    o.CustomerPurchaseOrderNumber = "MOOMOO 56384"; 
    o.EmailAddress = "[email protected]"; 
    o.DeliveryDate = DateTime.Now.AddDays(35); 

    Address address1 = new Address(); 
    //address1.AddressID = "Z0mmn01034"; 
    address1.AddressID = "E0000bbb6       "; 
    address1.OrganizationName = "          Nicks Organization "; 
    address1.AddressLine1 = "    143 E. WASHINGTON STREET    "; 
    address1.City = "   Rock  "; 
    address1.State = "MA      "; 
    address1.ZipCode = "       61114"; 
    address1.Country = "US    "; 

    o.ShipToAddress = address1; 
+0

@Darin无遗憾的是它仍然犯规了解筛选自定义对象。我需要一个通用的方法来做到这一点。 – 2012-03-14 18:07:08

+0

什么定义了“自定义对象”?你为什么不放弃“其他”的情况呢? – Michael 2012-03-14 18:07:33

+0

我有一个对象,例如称为地址它拥有地址数据。我有一个名为Order in Order的对象,有一个名为orderAddress的属性,返回类型Address。 – 2012-03-14 18:11:41

回答

2

您的测试typeof(object)将全部失败。

尝试这样的:

static void TrimObjectValues(object instance) 
{ 
    // if the instance is null we have nothing to do here 
    if (instance == null) 
    { 
     return; 
    } 

    var props = instance 
     .GetType() 
     .GetProperties(BindingFlags.Instance | BindingFlags.Public) 
     // Ignore indexers 
     .Where(prop => prop.GetIndexParameters().Length == 0) 
     // Must be both readable and writable 
     .Where(prop => prop.CanWrite && prop.CanRead); 

    foreach (PropertyInfo prop in props) 
    { 
     if (prop.PropertyType == typeof(string)) 
     { 
      // if we have a string property we trim it 
      string value = (string)prop.GetValue(instance, null); 
      if (value != null) 
      { 
       value = value.Trim(); 
       prop.SetValue(instance, value, null); 
      } 
     } 
     else 
     { 
      // if we don't have a string property we recurse 
      TrimObjectValues(prop.GetValue(instance, null)); 
     } 
    } 
} 

我也让该函数没有返回值,因为你是无论如何修改参数实例。

测试用例:

public enum OrderType 
{ 
    OnOrBefore 
} 

public class Order 
{ 
    public string OrderUniqueIdentifier { get; set; } 
    public string VendorName { get; set; } 
    public string SoldToCustomerID { get; set; } 
    public OrderType OrderType { get; set; } 
    public string CustomerPurchaseOrderNumber { get; set; } 
    public string EmailAddress { get; set; } 
    public DateTime DeliveryDate { get; set; } 
    public Address ShipToAddress { get; set; } 
} 

public class Address 
{ 
    public string AddressID { get; set; } 
    public string OrganizationName { get; set; } 
    public string AddressLine1 { get; set; } 
    public string City { get; set; } 
    public string State { get; set; } 
    public string ZipCode { get; set; } 
    public string Country { get; set; } 
} 

class Program 
{ 
    static void Main() 
    { 
     Order o = new Order(); 

     o.OrderUniqueIdentifier = "TYBDEU83e4e4Ywow"; 

     o.VendorName = "Kwhatever"; 
     o.SoldToCustomerID = "Abc98971"; 
     o.OrderType = OrderType.OnOrBefore; 
     o.CustomerPurchaseOrderNumber = "MOOMOO 56384"; 
     o.EmailAddress = "[email protected]"; 
     o.DeliveryDate = DateTime.Now.AddDays(35); 

     Address address1 = new Address(); 
     //address1.AddressID = "Z0mmn01034"; 
     address1.AddressID = "E0000bbb6       "; 
     address1.OrganizationName = "          Nicks Organization "; 
     address1.AddressLine1 = "    143 E. WASHINGTON STREET    "; 
     address1.City = "   Rock  "; 
     address1.State = "MA      "; 
     address1.ZipCode = "       61114"; 
     address1.Country = "US    "; 

     o.ShipToAddress = address1; 


     TrimObjectValues(o); 
    } 

    static void TrimObjectValues(object instance) 
    { 
     if (instance == null) 
     { 
      return; 
     } 

     var props = instance 
      .GetType() 
      .GetProperties(BindingFlags.Instance | BindingFlags.Public) 
      // Ignore indexers 
      .Where(prop => prop.GetIndexParameters().Length == 0) 
      // Must be both readable and writable 
      .Where(prop => prop.CanWrite && prop.CanRead); 

     foreach (PropertyInfo prop in props) 
     { 
      if (prop.PropertyType == typeof(string)) 
      { 
       string value = (string)prop.GetValue(instance, null); 
       if (value != null) 
       { 
        value = value.Trim(); 
        prop.SetValue(instance, value, null); 
       } 
      } 
      else 
      { 
       TrimObjectValues(prop.GetValue(instance, null)); 
      } 
     } 
    } 
} 

更新2:

看来你还想来处理对象的列表。你可以适应方法:

static void TrimObjectValues(object instance) 
{ 
    if (instance == null) 
    { 
     return; 
    } 

    var props = instance 
     .GetType() 
     .GetProperties(BindingFlags.Instance | BindingFlags.Public) 
     // Ignore indexers 
     .Where(prop => prop.GetIndexParameters().Length == 0) 
     // Must be both readable and writable 
     .Where(prop => prop.CanWrite && prop.CanRead); 

    if (instance is IEnumerable) 
    { 
     foreach (var element in (IEnumerable)instance) 
     { 
      TrimObjectValues(element); 
     } 
     return; 
    } 

    foreach (PropertyInfo prop in props) 
    { 
     if (prop.PropertyType == typeof(string)) 
     { 
      string value = (string)prop.GetValue(instance, null); 
      if (value != null) 
      { 
       value = value.Trim(); 
       prop.SetValue(instance, value, null); 
      } 
     } 
     else 
     { 
      TrimObjectValues(prop.GetValue(instance, null)); 
     } 
    } 
} 
+0

当他有一个具有Type对象属性的类时,他们不会失败(但由于上面的.Where()子句,他甚至不会有机会执行else语句)。 – Michael 2012-03-14 18:11:42

+0

我得到一个nullRefereneeException与此代码....对象引用未设置为对象的实例。 – 2012-03-14 18:16:07

+0

@NickLaMarca,我已经更新了我的答案,以便在方法开始时测试实例是否为null。如果您实际显示了您正在测试的对象树以及示例值,它也可能有所帮助。 – 2012-03-14 18:16:50

0

prop.PropertyType == typeof(object)是不行的,因为这样只会为object是真实的而不是派生类型。你将不得不写typeof(object).IsAssignableFrom(prop.PropertyType);但是,这适用于所有类型!放弃这两个条件(stringobject)。

注意:还可以放弃TrimObjectValues(prop);之前的条件。 (用else替代else if (...)

+0

在这种情况下,当他尝试将自定义对象转换为字符串时((字符串)prop.GetValue(instance,null)),他不会得到异常吗? – Michael 2012-03-14 18:10:14

+0

修剪前对字符串的测试是可以的,只有'else'后面的测试是多余的。 – 2012-03-14 18:14:55

0
public object TrimObjectValues(object instance) 
{ 
    if (instance is string) 
    { 
     instance = ((string)instance).Trim(); 

     return instance; 
    } 

    if (instance is IEnumerable) 
    { 
     foreach (var element in (IEnumerable)instance) 
     { 
      TrimObjectValues(element); 
     } 

     return instance; 
    } 

    var props = instance.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public) 
      // Ignore non-string properties 
      .Where(prop => prop.PropertyType == typeof(string) | prop.PropertyType is object) 
      // Ignore indexers 
      .Where(prop => prop.GetIndexParameters().Length == 0) 
      // Must be both readable and writable 
      .Where(prop => prop.CanWrite && prop.CanRead); 

    foreach (PropertyInfo prop in props) 
    { 
     if (prop.PropertyType == typeof(string)) 
     { 
      string value = (string)prop.GetValue(instance, null); 
      if (value != null) 
      { 
       value = value.Trim(); 
       prop.SetValue(instance, value, null); 
      } 
     } 
     else if (prop.PropertyType is object) 
     { 
      TrimObjectValues(prop.GetValue(instance, null)); 
     } 
    } 

    return instance; 
}