我有一个具有各种属性的对象模型MyObject。有一次,我有两个这样的MyObject实例:实例A和实例B.如果实例B具有非空值,我想将实例A中的属性复制并替换为实例B的属性。
如果我只有1个具有3个属性的类,没问题,我可以轻松地对其进行硬编码(这是我开始做的)。但实际上我有12个不同的对象模型,每个模型有10个属性。
这样做的好方法是什么?
答案 0 :(得分:41)
<强>更新强>
如果您需要经常调用此方法,请使用AutoMapper。 Automapper使用Reflection.Emit
构建动态方法,并且比反射快得多。'
您可以使用反射复制属性的值:
public void CopyValues<T>(T target, T source)
{
Type t = typeof(T);
var properties = t.GetProperties().Where(prop => prop.CanRead && prop.CanWrite);
foreach (var prop in properties)
{
var value = prop.GetValue(source, null);
if (value != null)
prop.SetValue(target, value, null);
}
}
我已将其设为通用以确保类型安全。如果要包含私有属性,则应使用覆盖Type.GetProperties(),指定绑定标记。
答案 1 :(得分:7)
我已经尝试了凯尔芬利的Merge Two Objects into an Anonymous Type,它的工作非常完美。
使用TypeMerger
合并就像
var obj1 = new {foo = "foo"};
var obj2 = new {bar = "bar"};
var mergedObject = TypeMerger.MergeTypes(obj1 , obj2 );
你得到了合并的对象,除此之外,还有一项规定可以忽略特定的属性。你也可以对MVC3使用相同的东西。
答案 2 :(得分:2)
你可以使用反射来做到这一点,但正如有人说的那样,它会有性能损失。
由于您正在使用预期的类设计,因此可以使用类似的扩展方法实现相同的目标:
public static class MyClassExtensions
{
public static void Merge(this MyClass instanceA, MyClass instanceB)
{
if(instanceA != null && instanceB != null)
{
if(instanceB.Prop1 != null)
{
instanceA.Prop1 = instanceB.Prop1;
}
if(instanceB.PropN != null)
{
instanceA.PropN = instanceB.PropN;
}
}
}
以后,代码中的某处:
someInstanceOfMyClass.Merge(someOtherInstanceOfMyClass);
在一天结束时,您已将此操作集中在扩展方法中,如果添加或删除类的属性,则只需修改扩展方法的实现,即可完成所有操作。
答案 3 :(得分:0)
这与@Bas答案相同,但对于合并2对象列表
public class Copycontents
{
public static void Work<T>(IList<T> targetList, IList<T> sourceList, Func<T, int> selector)
{
var matchingPrimaryKey = targetList.Select(x => selector(x)).ToList();
foreach (var thismatchingPrimaryKey in matchingPrimaryKey)
{
CopyValues<T>(targetList.Single(x => selector(x) == thismatchingPrimaryKey),
sourceList.Single(x => selector(x) == thismatchingPrimaryKey));
}
}
private static void CopyValues<T>(T target, T source)
{
Type t = typeof(T);
var properties = t.GetProperties().Where(prop => prop.CanRead && prop.CanWrite);
foreach (var prop in properties)
{
var value = prop.GetValue(source, null);
if (value != null)
prop.SetValue(target, value, null);
}
}
}
答案 4 :(得分:0)
我为此目的编写了自己的课程:ObjectMerger。
基本上它使用反射(因此可能很慢)。它还包含更多功能,例如解析循环引用的对象并合并它们。我的ObjectMerger还包含处理更复杂类的机制,如string1 = (1 1 1 4 10)
var total = parseFloat(0);
for(var j=0; j<string1.length; j++) {
total += parseFloat(string1.charAt(j));
}
或Delegate
。这些将被完全复制,类中的其他对象以递归方式合并。
语法如下:
MemberInfo
我很遗憾地说它不是按原样使用,因为由于我公司的限制,目前存储库中缺少一些外部库,但它们很容易被重写。我希望将来可以添加它们。
答案 5 :(得分:0)
您可以使用以下软件包:XASoft
使用foo.Merger(bar)方法 将2个对象组合成一个动态对象
Collecting mysqlclient
Using cached https://files.pythonhosted.org/packages/f4/f1/3bb6f64ca7a429729413e6556b7ba5976df06019a5245a43d36032f1061e/mysqlclient-1.4.2.post1.tar.gz
Building wheels for collected packages: mysqlclient
Building wheel for mysqlclient (setup.py) ... error
Complete output from command c:\users\adity\desktop\dev\blog\env\scripts\python.exe -u -c "import setuptools, tokenize;__file__='C:\\Users\\adity\\AppData\\Local\\Temp\\pip-install-wxr9hw0f\\mysqlclient\\setup.py';f=getattr(tokenize, 'open', open)(__file__);code=f.read().replace('\r\n', '\n');f.close();exec(compile(code, __file__, 'exec'))" bdist_wheel -d C:\Users\adity\AppData\Local\Temp\pip-wheel-zjrz983m --python-tag cp37:
running bdist_wheel
running build
running build_py
creating build
creating build\lib.win32-3.7
creating build\lib.win32-3.7\MySQLdb
copying MySQLdb\__init__.py -> build\lib.win32-3.7\MySQLdb
copying MySQLdb\_exceptions.py -> build\lib.win32-3.7\MySQLdb
copying MySQLdb\compat.py -> build\lib.win32-3.7\MySQLdb
copying MySQLdb\connections.py -> build\lib.win32-3.7\MySQLdb
copying MySQLdb\converters.py -> build\lib.win32-3.7\MySQLdb
copying MySQLdb\cursors.py -> build\lib.win32-3.7\MySQLdb
copying MySQLdb\release.py -> build\lib.win32-3.7\MySQLdb
copying MySQLdb\times.py -> build\lib.win32-3.7\MySQLdb
creating build\lib.win32-3.7\MySQLdb\constants
copying MySQLdb\constants\__init__.py -> build\lib.win32-3.7\MySQLdb\constants
copying MySQLdb\constants\CLIENT.py -> build\lib.win32-3.7\MySQLdb\constants
copying MySQLdb\constants\CR.py -> build\lib.win32-3.7\MySQLdb\constants
copying MySQLdb\constants\ER.py -> build\lib.win32-3.7\MySQLdb\constants
copying MySQLdb\constants\FIELD_TYPE.py -> build\lib.win32-3.7\MySQLdb\constants
copying MySQLdb\constants\FLAG.py -> build\lib.win32-3.7\MySQLdb\constants
running build_ext
building 'MySQLdb._mysql' extension
creating build\temp.win32-3.7
creating build\temp.win32-3.7\Release
creating build\temp.win32-3.7\Release\MySQLdb
C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\BIN\cl.exe /c /nologo /Ox /W3 /GL /DNDEBUG /MD -Dversion_info=(1,4,2,'post',1) -D__version__=1.4.2.post1 "-IC:\Program Files (x86)\MySQL\MySQL Connector C 6.1\include\mariadb" -Ic:\users\adity\appdata\local\programs\python\python37-32\include -Ic:\users\adity\appdata\local\programs\python\python37-32\include "-IC:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\INCLUDE" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.10240.0\ucrt" "-IC:\Program Files (x86)\Windows Kits\8.1\include\shared" "-IC:\Program Files (x86)\Windows Kits\8.1\include\um" "-IC:\Program Files (x86)\Windows Kits\8.1\include\winrt" /TcMySQLdb/_mysql.c /Fobuild\temp.win32-3.7\Release\MySQLdb/_mysql.obj /Zl /D_CRT_SECURE_NO_WARNINGS
_mysql.c
MySQLdb/_mysql.c(29): fatal error C1083: Cannot open include file: 'mysql.h': No such file or directory
error: command 'C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\BIN\\cl.exe' failed with exit status 2
----------------------------------------
Failed building wheel for mysqlclient
Running setup.py clean for mysqlclient
Failed to build mysqlclient
Installing collected packages: mysqlclient
Running setup.py install for mysqlclient ... error
Complete output from command c:\users\adity\desktop\dev\blog\env\scripts\python.exe -u -c "import setuptools, tokenize;__file__='C:\\Users\\adity\\AppData\\Local\\Temp\\pip-install-wxr9hw0f\\mysqlclient\\setup.py';f=getattr(tokenize, 'open', open)(__file__);code=f.read().replace('\r\n', '\n');f.close();exec(compile(code, __file__, 'exec'))" install --record C:\Users\adity\AppData\Local\Temp\pip-record-wtvbzmsb\install-record.txt --single-version-externally-managed --compile --install-headers c:\users\adity\desktop\dev\blog\env\include\site\python3.7\mysqlclient:
running install
running build
running build_py
creating build
creating build\lib.win32-3.7
creating build\lib.win32-3.7\MySQLdb
copying MySQLdb\__init__.py -> build\lib.win32-3.7\MySQLdb
copying MySQLdb\_exceptions.py -> build\lib.win32-3.7\MySQLdb
copying MySQLdb\compat.py -> build\lib.win32-3.7\MySQLdb
copying MySQLdb\connections.py -> build\lib.win32-3.7\MySQLdb
copying MySQLdb\converters.py -> build\lib.win32-3.7\MySQLdb
copying MySQLdb\cursors.py -> build\lib.win32-3.7\MySQLdb
copying MySQLdb\release.py -> build\lib.win32-3.7\MySQLdb
copying MySQLdb\times.py -> build\lib.win32-3.7\MySQLdb
creating build\lib.win32-3.7\MySQLdb\constants
copying MySQLdb\constants\__init__.py -> build\lib.win32-3.7\MySQLdb\constants
copying MySQLdb\constants\CLIENT.py -> build\lib.win32-3.7\MySQLdb\constants
copying MySQLdb\constants\CR.py -> build\lib.win32-3.7\MySQLdb\constants
copying MySQLdb\constants\ER.py -> build\lib.win32-3.7\MySQLdb\constants
copying MySQLdb\constants\FIELD_TYPE.py -> build\lib.win32-3.7\MySQLdb\constants
copying MySQLdb\constants\FLAG.py -> build\lib.win32-3.7\MySQLdb\constants
running build_ext
building 'MySQLdb._mysql' extension
creating build\temp.win32-3.7
creating build\temp.win32-3.7\Release
creating build\temp.win32-3.7\Release\MySQLdb
C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\BIN\cl.exe /c /nologo /Ox /W3 /GL /DNDEBUG /MD -Dversion_info=(1,4,2,'post',1) -D__version__=1.4.2.post1 "-IC:\Program Files (x86)\MySQL\MySQL Connector C 6.1\include\mariadb" -Ic:\users\adity\appdata\local\programs\python\python37-32\include -Ic:\users\adity\appdata\local\programs\python\python37-32\include "-IC:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\INCLUDE" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.10240.0\ucrt" "-IC:\Program Files (x86)\Windows Kits\8.1\include\shared" "-IC:\Program Files (x86)\Windows Kits\8.1\include\um" "-IC:\Program Files (x86)\Windows Kits\8.1\include\winrt" /TcMySQLdb/_mysql.c /Fobuild\temp.win32-3.7\Release\MySQLdb/_mysql.obj /Zl /D_CRT_SECURE_NO_WARNINGS
_mysql.c
MySQLdb/_mysql.c(29): fatal error C1083: Cannot open include file: 'mysql.h': No such file or directory
error: command 'C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\BIN\\cl.exe' failed with exit status 2
----------------------------------------
Command "c:\users\adity\desktop\dev\blog\env\scripts\python.exe -u -c "import setuptools, tokenize;__file__='C:\\Users\\adity\\AppData\\Local\\Temp\\pip-install-wxr9hw0f\\mysqlclient\\setup.py';f=getattr(tokenize, 'open', open)(__file__);code=f.read().replace('\r\n', '\n');f.close();exec(compile(code, __file__, 'exec'))" install --record C:\Users\adity\AppData\Local\Temp\pip-record-wtvbzmsb\install-record.txt --single-version-externally-managed --compile --install-headers c:\users\adity\desktop\dev\blog\env\include\site\python3.7\mysqlclient" failed with error code 1 in C:\Users\adity\AppData\Local\Temp\pip-install-wxr9hw0f\mysqlclient\
even if object list works fine too!
var objA = new { a = 1, b = 2, c = 3 };
var newObj = objA.Merger(new { a = "Hey", d = 4, e = 5 });
newObj.e = "There";
newObj.f = 6;
Console.WriteLine(JsonConvert.SerializeObject(newObj));
糟糕,看起来像JavaScript语言...