使函数递归

本文关键字:递归 函数 | 更新日期: 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);然而,这适用于所有类型!删除这两个条件(对于stringobject)。

注意:还要删除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;
}