C# 如何仅在属性已更改的情况下将数据从一个.NET实例复制到另一个.NET实例?

C# 如何仅在属性已更改的情况下将数据从一个.NET实例复制到另一个.NET实例?,c#,.net,C#,.net,我希望将数据从.NET类的一个实例复制到同一类的另一个实例,但仅复制已修改/更改的属性 例如 到目前为止,我已经为每个类中的每个属性创建了一个bool IsPropertyNameModified。当我执行复制时,如果IsPropertyNameModified为true,我仅设置值(在destinationFoo)。这是一个非常简单的代码摘要 对于集合,这非常难看,但我认为我需要禁止设置集合,只提供AddProduct(…)。。等方法添加 (基本上) 我希望使用事件更好地处理这个问题。甚至使用

我希望将数据从.NET类的一个实例复制到同一类的另一个实例,但仅复制已修改/更改的属性

例如

到目前为止,我已经为每个类中的每个属性创建了一个
bool IsPropertyNameModified
。当我执行
复制
时,如果
IsPropertyNameModified
true
,我仅设置值(在
destinationFoo
)。这是一个非常简单的代码摘要

对于集合,这非常难看,但我认为我需要禁止设置集合,只提供
AddProduct(…)
。。等方法添加

(基本上)

我希望使用
事件
更好地处理这个问题。甚至使用
IPropertyNotified
或其他东西。我甚至在考虑为我们使用的每种类型(基本上不是很多->
int/string/bool
类型)创建一个自定义类,该类具有值且
已修改
设置

我不知道哪条路更干净更好。我觉得我现在的方式太难闻了

更新(来自评论和q)
请不要因为
destinationFoo
是从数据库加载的事实而挂断电话。这是不相干的。我想说的一点是,
destinationFoo
有很多属性,其中数据已经设置好了。它充满了数据。现在,
sourceFoo
是同一个类,但只有三个已更改的属性。因此,需要复制这三个属性。并非所有其他97个默认值(想想
0
null
等)。这就是为什么我需要知道更改/修改了哪3个属性,因此,只复制这些属性。

像这样的东西怎么样。我创建了一个名为
ChangeTracker
的抽象类,用于跟踪列表中的更改

class Program
{
    static void Main(string[] args)
    {
        var foo = new Foo() { Name = "Glenn", Age = 34, Notes = "sample code" };
        Foo bar = new Foo();
        bar.Apply(foo.GetTrackedChanges());

        // ... 
    }
}

public class Foo : ChangeTracker
{
    public Foo()
    {
    }

    private int _age;

    public int Age
    {
        get { return _age; }
        set { _age = value; Track("Age", value); }
    }

    private string _name;

    public string Name
    {
        get { return _name; }
        set { _name = value; Track("Name", value); }
    }

    private string _notes;

    public string Notes
    {
        get { return _notes; }
        set { _notes = value; Track("Notes", value); }
    }

    private string _favoriteColor;

    public string FavoriteColor
    {
        get { return _favoriteColor; }
        set { _favoriteColor = value; Track("FavoriteColor", value); }
    }


}

// this abstract class does the work
public abstract class ChangeTracker : IChangeTrackerResetable
{
    protected List<Tuple<string, object>> _changes = new List<Tuple<string, object>>();
    public IEnumerable<Tuple<string, object>> GetTrackedChanges()
    {
        return _changes;
    }

    void IChangeTrackerResetable.Reset()
    {
        _changes.Clear();
    }

    protected void Track(string propname, object value)
    {
        _changes.Add(Tuple.Create(propname, value));
    }

    public void Apply(IEnumerable<Tuple<string, object>> changes)
    {
        var inst = this;
        var props = inst.GetType().GetProperties(System.Reflection.BindingFlags.Public);
        foreach(var ch in changes)
        {
            var property = props.FirstOrDefault(r => r.Name == ch.Item1);
            if (property != null)
            {
                property.SetValue(inst, ch.Item2);
            }
        }

        // reset afterwards
        var o = this as IChangeTrackerResetable;
        o.Reset();
    }
}

public interface IChangeTrackerResetable
{
    void Reset();
}
类程序
{
静态void Main(字符串[]参数)
{
var foo=new foo(){Name=“Glenn”,Age=34,Notes=“sample code”};
Foo-bar=新的Foo();
Apply(foo.gettrackdchanges());
// ... 
}
}
公共类Foo:ChangeTracker
{
公共食物(
{
}
私人互联网;
公共信息
{
获取{return\u age;}
设置{u age=value;跟踪(“age”,value);}
}
私有字符串\u名称;
公共字符串名
{
获取{return\u name;}
设置{u name=value;轨迹(“name”,value);}
}
私人字符串注释;
公共弦乐
{
获取{return\u notes;}
设置{u notes=value;跟踪(“notes”,value);}
}
私有字符串\u favoriteColor;
公共字符串收藏夹颜色
{
获取{return\u favoriteColor;}
设置{u favoriteColor=value;轨迹(“favoriteColor”,value);}
}
}
//这个抽象类完成这项工作
公共抽象类ChangeTracker:IChangeTrackerResetable
{
受保护列表_changes=新列表();
公共IEnumerable GetTrackChanges()
{
返回更改;
}
void IChangeTrackerResetable.Reset()无效
{
_更改。清除();
}
受保护的无效轨迹(字符串名称、对象值)
{
_changes.Add(Tuple.Create(propname,value));
}
公共无效应用(IEnumerable更改)
{
var inst=此;
var props=inst.GetType().GetProperties(System.Reflection.BindingFlags.Public);
foreach(变化中的var ch)
{
var属性=props.FirstOrDefault(r=>r.Name==ch.Item1);
if(属性!=null)
{
属性设置值(仪表,第2章);
}
}
//事后重置
var o=此为IChangeTrackerResetable;
o、 重置();
}
}
公共接口IChangeTrackerResetable
{
无效重置();
}

是否通过某种UI编辑
sourceFoo
destinationFoo
,或者您只是从文件加载一个,从数据库加载另一个,然后比较它们?哪一个需要事件处理程序?您希望获得什么好处?e、 g.业绩?更少的网络流量?您是否希望将已更改的补丁应用到另一个实例,并进行自身的更改?显然感觉像是过早的优化,而且代码气味非常强烈。我认为您有三个选择:继续您正在做的事情,这感觉像是一个巨大的维护难题;在属性发生更改时使用observables/Rx触发事件;在任何属性发生更改时克隆对象。我很难理解为什么有人要将db项复制到文件中,或者反之亦然。RDBMS中DB的全部意义在于将数据存储在一个文件中,并在其上添加一种查询语言。除非这是为了某种迁移过程,比如获取旧数据库的XML转储并将其导入新数据库。在这种情况下,实体框架将自动处理“跟踪”。TLDR,知道这样做的目的将有助于我们提供更好的解决方案。这是MVVM中模式的一个非常粗糙、快速的n-dirty版本,特别是我熟悉MVVMLight,实现InotifyPropertyChanged的ViewModelBase类我从未使用过它,但快速的nuget搜索使我更改了跟踪和描述“跟踪poco对象和集合中的更改”。它依赖于Castle.Core,并且有一个类似于实体框架打开/关闭跟踪的AsTrack扩展。是的,我同意Track()调用可以在Foo的OnpropertyChanged()中通过[CallerMemberName]实现INPC时完成这样就不会有任何拼写错误的属性名称用于跟踪。
public class Foo : Baa
{
    private int _age;
    public int Age { get { return _age; } set { _age = value; IsAgeModified = true; }
    public bool IsAgeModified { get; set; }
}
class Program
{
    static void Main(string[] args)
    {
        var foo = new Foo() { Name = "Glenn", Age = 34, Notes = "sample code" };
        Foo bar = new Foo();
        bar.Apply(foo.GetTrackedChanges());

        // ... 
    }
}

public class Foo : ChangeTracker
{
    public Foo()
    {
    }

    private int _age;

    public int Age
    {
        get { return _age; }
        set { _age = value; Track("Age", value); }
    }

    private string _name;

    public string Name
    {
        get { return _name; }
        set { _name = value; Track("Name", value); }
    }

    private string _notes;

    public string Notes
    {
        get { return _notes; }
        set { _notes = value; Track("Notes", value); }
    }

    private string _favoriteColor;

    public string FavoriteColor
    {
        get { return _favoriteColor; }
        set { _favoriteColor = value; Track("FavoriteColor", value); }
    }


}

// this abstract class does the work
public abstract class ChangeTracker : IChangeTrackerResetable
{
    protected List<Tuple<string, object>> _changes = new List<Tuple<string, object>>();
    public IEnumerable<Tuple<string, object>> GetTrackedChanges()
    {
        return _changes;
    }

    void IChangeTrackerResetable.Reset()
    {
        _changes.Clear();
    }

    protected void Track(string propname, object value)
    {
        _changes.Add(Tuple.Create(propname, value));
    }

    public void Apply(IEnumerable<Tuple<string, object>> changes)
    {
        var inst = this;
        var props = inst.GetType().GetProperties(System.Reflection.BindingFlags.Public);
        foreach(var ch in changes)
        {
            var property = props.FirstOrDefault(r => r.Name == ch.Item1);
            if (property != null)
            {
                property.SetValue(inst, ch.Item2);
            }
        }

        // reset afterwards
        var o = this as IChangeTrackerResetable;
        o.Reset();
    }
}

public interface IChangeTrackerResetable
{
    void Reset();
}