使函数递归

时间:2012-03-14 17:59:48

标签: c# recursion

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

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))

此代码不起作用的原因是一个例子是我传递的对象,因为输入有一个返回“地址”类型的属性,因此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;

3 个答案:

答案 0 :(得分: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 = "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));
        }
    }
}

答案 1 :(得分:0)

prop.PropertyType == typeof(object)不起作用,因为这只适用于object而不适用于派生类型。你必须写typeof(object).IsAssignableFrom(prop.PropertyType);但是,这适用于所有类型!删除这两个条件(适用于stringobject)。

注意:同时删除TrimObjectValues(prop);之前的条件。 (将else if (...)替换为else

答案 2 :(得分: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;
}