C# 有一种方法可以更新对象的所有属性,只更改它的值吗?

C# 有一种方法可以更新对象的所有属性,只更改它的值吗?,c#,reflection,C#,Reflection,我有一个例子: public class User { public int Id { get; set; } public string Name { get; set; } public List<Car> Cars { get; set; } public List<User> Children { get; set; } } public class Car { public int Id { get; set; }

我有一个例子:

public class User
{
    public int Id { get; set; }
    public string Name { get; set; }

    public List<Car> Cars { get; set; }
    public List<User> Children { get; set; }
}

public class Car
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Color { get; set; }
}
公共类用户
{
公共int Id{get;set;}
公共字符串名称{get;set;}
公共列表车辆{get;set;}
公共列表子项{get;set;}
}
公车
{
公共int Id{get;set;}
公共字符串名称{get;set;}
公共字符串颜色{get;set;}
}
因此,有一种方法可以更新
用户
对象,更新它
子对象
汽车
? 如果要更新的对象中没有与新对象中相同的汽车,则添加该汽车,但如果要更新的对象中有汽车,而新对象中没有汽车,则将其从要更新的对象中删除,并更新所有匹配汽车的所有属性,以及
子属性


有可能吗?

最简单的方法是只设置目标对象中的
Cars
Children
属性,以引用源对象中的
Cars
Children
列表

originalUser.Cars = changedUser.Cars;
originalUser.Children = changedUser.Children;
如果对象是在不同的ORM上下文中创建的,那么这可能是不可能的

另一种方法是比较列表并适当修改对象。您需要编写一个方法来执行此操作。林克会很有帮助的

更新

下面是一个快速而肮脏(可能效率很低)的扩展方法,可能很有用:

public void UpdateUser(this User user, User changedUser)
{
    var changedUserCarIDs = changedUser.Cars.Select(c => c.Id).ToArray();
    user.Cars = user.Cars.Where(c => changedUserCarIDs.Contains(c.Id)).ToList();
    foreach (var changedCar in changedUser.Cars)
    {
        var car = user.Cars.SingleOrDefault(c => c.Id == changedCar.Id);
        if (car == null) user.Cars.Add(car = new Car());
        car.Name = changedCar.Name;
        car.Color = changedCar.Color;
    }
}

要查找添加和删除的内容,请执行以下操作:

var removedCars = orgUser.Cars.Except(changedUser.Cars);
var addedCars = changedUser.Cars.Except(orgUser.Cars);
使用相等比较器重载查找所有已更改的车辆:


为孩子们做同样的事情。

是的!这里的解决方案是可能的(此解决方案更新所有属性、类属性和集合属性,但如果其中有类,则该类需要继承抽象实体):

private void updatealProperty(entityType currentEntity,entityType newEntity)
其中idType:IEquatable
其中entityType:AbstractEntity
{
var currentEntityProperties=currentEntity.GetType().GetProperties();
var newEntityProperties=newEntity.GetType().GetProperties();
foreach(currentEntityProperty中的var currentEntityProperty)
{
foreach(newEntityProperty中的var newEntityProperty)
{
if(newEntityProperty.Name==currentEntityProperty.Name)
{
如果(currentEntityProperty.PropertyType.BaseType.IsGenericType&&
currentEntityProperty.PropertyType.BaseType.GetGenericTypeDefinition()==typeof(AbstractEntity))
{
var idPropertyType=currentEntityProperty.PropertyType.GetProperty(“Id”).PropertyType;
var entityPropertyType=currentEntityProperty.PropertyType;
this.InvokeUpdateAllProperties(currentEntityProperty.GetValue(currentEntity,null),
newEntityProperty.GetValue(newEntity,null),
idPropertyType、entityPropertyType);
打破
}
else if(currentEntityProperty.PropertyType.GetInterfaces().Any(
x=>x.IsGenericType&&
x、 GetGenericTypeDefinition()==typeof(ICollection)))
{
dynamic currentCollection=currentEntityProperty.GetValue(currentEntity,null);
动态newCollection=newEntityProperty.GetValue(newEntity,null);
this.UpdateCollectionItems(currentEntityProperty、currentCollection、newCollection);
DynamicItemStoreMove=Enumerable.ToList(Enumerable.Except(currentCollection,newCollection));
DynamicItemsToAdd=Enumerable.ToList(Enumerable.Except(newCollection,currentCollection));
DynamicItemsAreeQual=Enumerable.ToList(Enumerable.Intersect(currentCollection,newCollection));
for(int i=0;ix.IsGenericType&&
x、 GetGenericTypeDefinition()==typeof(ICollection)).First();
var argumentType=collectionType.GetGenericArguments()[0];
如果(argumentType.BaseType.IsGenericType)&&
argumentType.BaseType.GetGenericTypeDefinition()==typeof(AbstractEntity))
{
foreach(currentCollection中的var currentItem)
{
foreach(newCollection中的var newItem)
{
if(currentItem.Equals(newItem))
{
var idPropertyType=currentItem.GetType().GetProperty(“Id”).PropertyType;
var entityPropertyType=currentItem.GetType();
InvokeUpdateAllProperties(currentItem、newItem、idPropertyType、entityPropertyType);
}
}
}
}
}
私有void InvokeUpdateAllProperties(动态currentEntity、动态newEntity、动态idPropertyType、动态entityPropertyType)
{
var method=this.GetType().GetMethod(“UpdateAllProperties”,BindingFlags.Instance | BindingFlags.NonPublic);
var一般方法
private void UpdateAllProperties<idType, entityType>(entityType currentEntity, entityType newEntity)
    where idType : IEquatable<idType>
    where entityType : AbstractEntity<idType>
{
    var currentEntityProperties = currentEntity.GetType().GetProperties();
    var newEntityProperties = newEntity.GetType().GetProperties();

    foreach (var currentEntityProperty in currentEntityProperties)
    {
        foreach (var newEntityProperty in newEntityProperties)
        {
            if (newEntityProperty.Name == currentEntityProperty.Name)
            {
                if (currentEntityProperty.PropertyType.BaseType.IsGenericType &&
                    currentEntityProperty.PropertyType.BaseType.GetGenericTypeDefinition() == typeof(AbstractEntity<>))
                {
                    var idPropertyType = currentEntityProperty.PropertyType.GetProperty("Id").PropertyType;
                    var entityPropertyType = currentEntityProperty.PropertyType;

                    this.InvokeUpdateAllProperties(currentEntityProperty.GetValue(currentEntity, null),
                                                    newEntityProperty.GetValue(newEntity, null),
                                                    idPropertyType, entityPropertyType);

                    break;
                }
                else if (currentEntityProperty.PropertyType.GetInterfaces().Any(
                            x => x.IsGenericType &&
                                    x.GetGenericTypeDefinition() == typeof(ICollection<>)))
                {
                    dynamic currentCollection = currentEntityProperty.GetValue(currentEntity, null);
                    dynamic newCollection = newEntityProperty.GetValue(newEntity, null);

                    this.UpdateCollectionItems(currentEntityProperty, currentCollection, newCollection);

                    dynamic itemsToRemove = Enumerable.ToList(Enumerable.Except(currentCollection, newCollection));
                    dynamic itemsToAdd = Enumerable.ToList(Enumerable.Except(newCollection, currentCollection));
                    dynamic itemsAreEqual = Enumerable.ToList(Enumerable.Intersect(currentCollection, newCollection));

                    for (int i = 0; i < itemsToRemove.Count; i++)
                    {
                        currentCollection.Remove(Enumerable.ElementAt(itemsToRemove, i));
                    }

                    for (int i = 0; i < itemsToAdd.Count; i++)
                    {
                        currentCollection.Add(Enumerable.ElementAt(itemsToAdd, i));
                    }

                    break;
                }
                else
                {
                    currentEntityProperty.SetValue(currentEntity, newEntityProperty.GetValue(newEntity, null), null);

                    break;
                }
            }
        }
    }
}

private void UpdateCollectionItems(PropertyInfo currentEntityProperty, dynamic currentCollection, dynamic newCollection)
{
    var collectionType = currentEntityProperty.PropertyType.GetInterfaces().Where(
                            x => x.IsGenericType &&
                                    x.GetGenericTypeDefinition() == typeof(ICollection<>)).First();

    var argumentType = collectionType.GetGenericArguments()[0];

    if (argumentType.BaseType.IsGenericType &&
        argumentType.BaseType.GetGenericTypeDefinition() == typeof(AbstractEntity<>))
    {
        foreach (var currentItem in currentCollection)
        {
            foreach (var newItem in newCollection)
            {
                if (currentItem.Equals(newItem))
                {
                    var idPropertyType = currentItem.GetType().GetProperty("Id").PropertyType;
                    var entityPropertyType = currentItem.GetType();

                    this.InvokeUpdateAllProperties(currentItem, newItem, idPropertyType, entityPropertyType);
                }
            }
        }
    }
}

private void InvokeUpdateAllProperties(dynamic currentEntity, dynamic newEntity, dynamic idPropertyType, dynamic entityPropertyType)
{
    var method = this.GetType().GetMethod("UpdateAllProperties", BindingFlags.Instance | BindingFlags.NonPublic);
    var genericMethod = method.MakeGenericMethod(idPropertyType, entityPropertyType);
    genericMethod.Invoke(this, new[] { currentEntity, newEntity });
}
public abstract class AbstractEntity<idType>
    where idType : IEquatable<idType>
{
    public idType Id { get; set; }
}
public class User : AbstractEntity<int>
{
    public string Name { get; set; }
    public List<Car> OtherCars { get; set; }
    public Car MainCar { get; set; }

    public bool Equals(Car other)
    {
        if (this.Id == other.Id)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
}

public class Car : AbstractEntity<int>
{
    public string Name { get; set; }
    public string Color { get; set; }

    public bool Equals(Car other)
    {
        if (this.Id == other.Id)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
}
User currentUser = new User()
{
    Id = 1,
    Name = "Vinicius",
    OtherCars = new List<Car>()
    {
        new Car()
        {
            Id = 2,
            Name = "Corsa II",
            Color = "Azul"
        },
        new Car()
        {
            Id = 3,
            Name = "Palio",
            Color = "Vermelho"
        },
        new Car()
        {
            Id = 4,
            Name = "Fusca",
            Color = "Azul"
        }
    },
    MainCar = new Car()
    {
        Id = 1,
        Name = "Corsa",
        Color = "Preto"
    }
};

User updatedUser = new User()
{
    Id = 1,
    Name = "Vinicius Ottoni",
    OtherCars = new List<Car>()
    {
        new Car()
        {
            Id = 5,
            Name = "Voyage",
            Color = "Azul"
        },
        new Car()
        {
            Id = 6,
            Name = "Voyage II",
            Color = "Vermelho"
        },
        new Car()
        {
            Id = 4,
            Name = "Fusca",
            Color = "Rosa"
        }
    },
    MainCar = new Car()
    {
        Id = 2,
        Name = "Voyage",
        Color = "Vinho"
    }
};

this.UpdateAllProperties<int, User>(currentUser, updatedUser);