使用反射

时间:2016-02-05 22:43:27

标签: c# .net recursion system.reflection

我正在对象上编写一个扩展方法TrimSpaces,以便它递归地应该能够修剪空格。我成功地修剪了第一级对象的空间,但是,我无法对子对象做同样的事情。

作为示例,请考虑以下类

public class Employee
{
    public string EmployeeID { get; set; }
    public string EmployeeName { get; set; }
    public DateTime HireDate { get; set; }
    public Department EmployeeDepartment { get; set; }
}

public class Department
{
    public int DepartmentID { get; set; }
    public string DepartmentName { get; set; }
}

在上面的课程中,我目前能够从Employee类属性中修剪空格,但我无法修剪DepartmentName

这是我写的代码

    public static T TrimSpaces<T>(this T obj)
    {
        var properties = obj.GetType()
            .GetProperties(BindingFlags.Instance | BindingFlags.Public)
            .Where(prop => prop.PropertyType == typeof(string))
            .Where(prop => prop.CanWrite && prop.CanRead);
        foreach (var property in properties)
        {
            var value = (string)property.GetValue(obj, null);
            if (value.HasValue())
            {
                var newValue = (object)value.Trim();
                property.SetValue(obj, newValue, null);
            }
        }


        var customTypes =
            obj.GetType()
                .GetProperties(BindingFlags.Instance | BindingFlags.Public)
                .Where(
                    prop =>
                        !prop.GetType().IsPrimitive && prop.GetType().IsClass &&
                        !prop.PropertyType.FullName.StartsWith("System"));

        foreach (var customType in customTypes)
        {
            ((object)customType.GetValue(obj).GetType()).TrimSpaces();
        }

        return obj;
    }

2 个答案:

答案 0 :(得分:2)

循环浏览属性时,您将调用以下行:

((object)customType.GetValue(obj).GetType()).TrimSpaces(); 

调用TrimSpaces将对象的类型作为obj传递。相反,你应该像这样传递自己的对象:

((object)customType.GetValue(obj)).TrimSpaces();

在这种情况下,不需要转换为object,所以你可以拥有:

customType.GetValue(obj).TrimSpaces();

答案 1 :(得分:0)

  

正如Yacoub指出的那样,我使用了GetValue然后调用了   TrimSpaces。就像上次我试图这样做的那样,我   得到了一个空引用异常。我写了一个空检查   开始的方法避免相同。另外,由于我的原因   我还不知道,我得到了#34; TargetParameterCountException&#34;。对于   我已经添加了一个检查我正在搜索的customType应该   不是原始类型。通过这些更改,代码似乎可以正常工作。

     

作为旁注,我计划修剪的对象是   复杂的深嵌套对象,具有各种用户定义的类   具有至少5级深嵌套的属性。我还没到   弄清楚为什么发生空引用异常以及   TargetParameterCountException

     

以下是我正在使用的最终代码。我会这样做   如果我有任何错误修复,请更新此答案

确定。我已经弄清楚问题是什么,下面是更新评论的代码。我也将保留旧代码,以便将来查看此问题的任何人都知道上下文

 public static T TrimSpaces<T>(this T obj)
    {
        if (obj == null)
        {
            return obj;
        }

        //Iterates all properties and trims the values if they are strings
        var properties = obj.GetType()
            .GetProperties(BindingFlags.Instance | BindingFlags.Public)
            .Where(prop => prop.PropertyType == typeof(string))
            .Where(prop => prop.CanWrite && prop.CanRead);

        foreach (var property in properties)
        {
            var value = (string)property.GetValue(obj, null);
            if (value.HasValue())
            {
                var newValue = (object)value.Trim();
                property.SetValue(obj, newValue, null);
            }
        }


        // This is to take care of Lists. This iterates through each value
        // in the list.
        // For example, Countries which is a List<Country>
        var baseTypeInfo = obj.GetType().BaseType;
        if (baseTypeInfo != null && baseTypeInfo.FullName.Contains("List"))
        {
            int listCount = (int)obj.GetType().GetProperty("Count").GetValue(obj, null);
            for (int innerIndex = 0; innerIndex < listCount; innerIndex++)
            {
                object item = obj.GetType()
                    .GetMethod("get_Item", new Type[] { typeof(int) })
                    .Invoke(obj, new object[] { innerIndex });
                item.TrimSpaces();
            }
        }


        // Now once we are in a complex type (for example Country) it then needs to
        // be trimmed recursively using the initial peice of code of this method
        // Hence if it is a complex type we are recursively calling TrimSpaces
        var customTypes =
            obj.GetType()
                .GetProperties(BindingFlags.Instance | BindingFlags.Public)
                .Where(
                    prop =>
                        !prop.GetType().IsPrimitive && prop.GetType().IsClass &&
                        !prop.PropertyType.FullName.StartsWith("System"));

        foreach (var customType in customTypes)
        {
            // If it's a collection, let the about piece of code take care
            // Only, normal types like, Code etc will be trimmed
            if (customType.GetIndexParameters().Length == 0)
            {
                customType.GetValue(obj).TrimSpaces();
            }
        }

        return obj;
    }

旧代码:

public static T TrimSpaces<T>(this T obj)
    {

        if (obj == null)
        {
            return obj;
        }

        var properties = obj.GetType()
            .GetProperties(BindingFlags.Instance | BindingFlags.Public)
            .Where(prop => prop.PropertyType == typeof(string))
            .Where(prop => prop.CanWrite && prop.CanRead);
        foreach (var property in properties)
        {
            var value = (string)property.GetValue(obj, null);
            if (value.HasValue())
            {
                var newValue = (object)value.Trim();
                property.SetValue(obj, newValue, null);
            }
        }


        var customTypes =
            obj.GetType()
                .GetProperties(BindingFlags.Instance | BindingFlags.Public)
                .Where(
                    prop =>
                        !prop.GetType().IsPrimitive && prop.GetType().IsClass &&
                        !prop.PropertyType.FullName.StartsWith("System"));

        foreach (var customType in customTypes)
        {
            if (customType.Name.Contains("Item"))
            {
                continue;
            }

            customType.GetValue(obj).TrimSpaces();
        }

        return obj;
    }