简体   繁体   English

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

[英]Set Object null if all its properties are null in C#

I want to write a function which it turns every properies and child properties of an object. 我想编写一个函数,该函数可以转换对象的所有属性和子属性。 And if all properties of one property are null, then I will set that property as null. 而且,如果一个属性的所有属性都为null,那么我将该属性设置为null。 I will explain with one example. 我将举例说明。

For example, if both TeacherName and TeacherSurname are null then I want to set Teacher to null. 例如,如果TeacherNameTeacherSurname都为null,那么我想将Teacher设置为null。 Then, if ExamMark and ExamName and Teacher are null, then Exam will be null. 然后,如果ExamMarkExamName以及Teacher为空,则Exam将为空。

You can see json version of like my question from this link Json Version 您可以从此链接查看喜欢我的问题的json版本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; }

}

I wrote this method. 我写了这个方法。 But this doing only first step. 但这只是第一步。 But I need recursive for child class. 但是我需要递归的孩子上课。 How can I convert this method to recursive? 如何将这种方法转换为递归?

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;
}

using Generics and Reflection. 使用泛型和反射。

    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;
    }

Here you can call it 在这里你可以称之为

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

What you're asking for is actually an anti-pattern. 您要的实际上是一种反模式。 What this does is it propagates the requirement for tons of null checks in your code. 这是在代码中传播大量空检查的要求。 Not only do you have to check if all properties are null, you also have to check if your object is null when you want to use it. 您不仅需要检查所有属性是否为null,而且还必须在要使用它时检查对象是否为null。 Also reflection is very slow and if you're doing this often, you'll bog down your application. 同样,反射非常慢,如果经常这样做,您将陷入困境。

You should look into the Null Object Pattern . 您应该查看Null对象模式 It basically does what you want it to, and you remove all those pesky null checks: 它基本上完成了您想要的操作,并且删除了所有这些讨厌的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,
    }
}

You can do this for each object in your code that acts this way (you can see that I did it on your nested Address and Exam types as well) and then instead of doing this: 您可以对代码中以此方式起作用的每个对象执行此操作(您可以看到我也对嵌套的Address和Exam类型执行了此操作),然后而不是这样做:

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

You can do this: 你可以这样做:

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

This leads to clearer code, your intent stands out more, and you can specifically define in each object what constitutes as null. 这样可以使代码更清晰,您的意图更加突出,并且您可以在每个对象中专门定义构成null的内容。

Have a look at this The GetValueOrNull should work and do what you need, not tested with all possible use cases but it oculd be tweaked a little if doesn't work in all cases 看看这个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;
}

call it as follows 称它为

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

hope it helps :) 希望能帮助到你 :)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM