如果Object的所有属性在C#中为null,则将其设置为null

时间:2018-12-12 14:24:09

标签: c# asp.net asp.net-mvc

我想编写一个函数,该函数可以转换对象的所有属性和子属性。而且,如果一个属性的所有属性都为null,那么我将该属性设置为null。我将举一个例子来解释。

例如,如果TeacherNameTeacherSurname都为空,那么我想将Teacher设置为空。然后,如果ExamMarkExamNameTeacher为空,则Exam将为空。

您可以从此链接Json Version看到类似我的问题的json版本

public class Student
{
    public string Name { get; set; }
    public string Surname { get; set; }
    public Address Address { get; set; }
    public Exam Exam { get; set; }
}

public class Exam
{
    public string ExamMark { get; set; }
    public string ExamName { get; set; }
    public Teacher Teacher { get; set; }
}

public class Teacher
{
    public string TeacherName { get; set; }
    public string TeacherSurname { get; set; }
}

public class Address
{
    public string Country { get; set; }
    public string City { get; set; }

}

我写了这种方法。但这只是第一步。但是我需要递归的孩子上课。如何将这种方法转换为递归?

public static object ConvertToNull(object obj)
{
    Type objType = obj.GetType();
    PropertyInfo[] properties = objType.GetProperties();

    var mainClassProperties = properties.Where(p => p.PropertyType.Assembly == objType.Assembly);

    foreach (var mainClassProperty in mainClassProperties)
    {
       object propValue = mainClassProperty.GetValue(obj, null);
       var classAllProperties = propValue.GetType().GetProperties();

       if (propValue.GetType().GetProperties().All(propertyInfo => propertyInfo.GetValue(propValue) == null))
       {
           mainClassProperty.SetValue(obj, null);
       }
   }
    return obj;
}

3 个答案:

答案 0 :(得分:2)

使用泛型和反射。

    public T ConvertToNull<T>(T model) where T : class
    {
        if (model == null) return null;
        Type type = model.GetType();
        PropertyInfo[] properties =  type.GetProperties();

        var valueTypes = properties.Where(p => p.PropertyType.Assembly != type.Assembly);
        var nonValueTypes = properties.Where(p => p.PropertyType.Assembly == type.Assembly);

        foreach (var nonValueType in nonValueTypes)
            nonValueType.SetValue(model, ConvertToNull(nonValueType.GetValue(model)));

        if (valueTypes.All(z => z.GetValue(model) == null) && nonValueTypes.All(z => z.GetValue(model) == null))
            return null;
        else
            return model;
    }

在这里您可以调用它

        List<Student> students = new List<Student>();
        Student student = new Student() { Name = "StudentName", Surname = "StudentSurname", Address = new Address() { City = "City", Country = "Country" }, Exam = new Exam() { ExamMark = "ExamMark", ExamName = "ExamName", Teacher = new Teacher() { TeacherName = "TeacherName", TeacherSurname = "TeacherSurname" } } };

        Student student2 = new Student() { Name = "StudentName", Surname = "StudentSurname", Address = new Address(), Exam = new Exam() { ExamMark = "ExamMark", ExamName = "ExamName", Teacher = new Teacher() } };

        students.Add(student);
        students.Add(student2);

        List<Student> results = new List<Student>();
        foreach (var item in students)
        {
            var result = ConvertToNull(item);
            results.Add(result);
        }

答案 1 :(得分:1)

您要的实际上是一种反模式。这是在代码中传播大量空检查的要求。您不仅需要检查所有属性是否为null,而且还必须在要使用它时检查对象是否为null。另外,反射速度非常慢,如果您经常这样做,则会使应用程序陷入困境。

您应该查看Null Object Pattern。它基本上完成了您想要的操作,并且删除了所有那些讨厌的null检查:

public class Student
{
    public string Name { get; set; }
    public string Surname { get; set; }
    public Address Address { get; set; }
    public Exam Exam { get; set; }
    public static Student NullStudent { get; } = new Student
    {
        Name = null,
        Surname = null,
        Address = Address.NullAddress,
        Exam = Exam.NullExam,
    }
}

您可以对代码中以此方式起作用的每个对象执行此操作(您也可以看到我也对嵌套的Address和Exam类型执行了此操作),然后不要这样做:

if (Student.EverythingIsNull) { Student = null }
if (Student is null) { //do null stuff }

您可以这样做:

if (item == Student.NullStudent) { //do null stuff }

这将导致代码更清晰,您的意图更加突出,并且您可以在每个对象中专门定义什么构成null。

答案 2 :(得分:1)

看看这个GetValueOrNull应该可以工作并做您需要的事情,没有对所有可能的用例进行测试,但是如果不能在所有情况下都不起作用,则可能需要进行一些调整

public static bool IsSimpleType(Type type)
{
    return
        type.IsPrimitive ||
        new Type[] {
    typeof(Enum),
    typeof(String),
    typeof(Decimal),
    typeof(DateTime),
    typeof(DateTimeOffset),
    typeof(TimeSpan),
    typeof(Guid)
        }.Contains(type) ||
        Convert.GetTypeCode(type) != TypeCode.Object ||
        (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>) && IsSimpleType(type.GetGenericArguments()[0]))
        ;
}
public object GetValueOrNull(object obj)
{
    if (obj == null) return null;
    Type objType = obj.GetType();
    PropertyInfo[] properties = objType.GetProperties();
    var simpleTypes = properties.Where(t => IsSimpleType(t.PropertyType));

    var nonValueTypes = properties.Where(p => !simpleTypes.Contains(p));
    foreach (var child in nonValueTypes)
    {
        child.SetValue(obj, GetValueOrNull(child.GetValue(obj)));
    }
    return simpleTypes.All(z => z.GetValue(obj) == null) && nonValueTypes.All(z => z.GetValue(obj) == null) ? null : obj;
}

称呼它

var student = new Student { Address = new Address { }, Exam = new Exam { Teacher = new Teacher() } };
            var test = GetValueOrNull(student);

希望它会有所帮助:)