使函数递归
本文关键字:递归 函数 | 更新日期: 2023-09-27 18:27:52
如果输入对象中有返回自定义对象的属性,则以下函数需要查看该对象内部,还需要对该对象进行修剪。下面的代码适用于输入对象,但不会递归地查看返回自定义对象的属性并执行修剪过程。
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 = "abc@electric.com";
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;
您的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 = "abc@electric.com";
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));
}
}
}
prop.PropertyType == typeof(object)
不起作用,因为这只适用于object
,而不适用于派生类型。您必须编写typeof(object).IsAssignableFrom(prop.PropertyType)
;然而,这适用于所有类型!删除这两个条件(对于string
和object
)。
注意:还要删除TrimObjectValues(prop);
之前的条件。(用else
替换else if (...)
)
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;
}