简体   繁体   English

如何将属性从一个 object 复制到另一个具有不同值 C#

[英]how to copy properties from one object to another with different values C#

I want to copy the values of Properties in a given object ClassA to another object instance called ClassB , these classes may or may not be the same type.我想将给定 object ClassA中的 Properties 值复制到另一个名为ClassB的 object 实例中,这些类可能是也可能不是同一类型。

if a property in ClassB has a value and in ClassA the corresponding property value is null, then do not copy that value, so only copy across where the current property in ClassB is null.如果ClassB中的属性有值,而ClassA中对应的属性值为 null,则不要复制该值,因此仅复制ClassB中的当前属性为 null 的位置。

This is NOT a clone exercise, the target object ( ClassB ) is already instantiated with partially defined values, I'm looking for a reusable way to copy across the rest of the values that were not already set.这不是克隆练习,目标 object ( ClassB ) 已经用部分定义的值实例化,我正在寻找一种可重用的方法来复制尚未设置的值的 rest。

Think of testing scenarios where we have a common or default test data value, for specific tests I want to set some specific fields, then finish setting the other properties from the common test data object.想想我们有一个通用或默认测试数据值的测试场景,对于特定的测试我想设置一些特定的字段,然后从通用测试数据 object 中完成设置其他属性。

I think I am looking for a Reflection based solution, as that way we would not need to know the specific types to copy, which would make it reusable for many different scenarios.我想我正在寻找一个基于反射的解决方案,因为这样我们就不需要知道要复制的特定类型,这将使它可以在许多不同的场景中重用。

eg.例如。

public class Employee
{
    public int EmployeeID { get; set; }
    public string EmployeeName { get; set; }
    public Address ContactAddress { get; set; }
}

public class Address
{
    public string Address1 { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    public string ZipCode { get; set; }
}

test eg.测试例如。

public void TestMethod1()
{
    Employee employee = new Employee();
    employee.EmployeeID = 100;
    employee.EmployeeName = "John";
    employee.ContactAddress = new Address();
    employee.ContactAddress.Address1 = "Park Ave";
    employee.ContactAddress.City = "New York";
    employee.ContactAddress.State = "NewYork";
    employee.ContactAddress.ZipCode = "10002";
 
    Employee employeeCopy = new Employee();
    employeeCopy.EmployeeID = 101;
    employeeCopy.EmployeeName = "Tom";
    employeeCopy.ContactAddress = new Address();

    CopyPropertiesTo(employee, employeeCopy);
}

I want to get the result我想得到结果

employeeCopy EmployeeID=101;员工复制员工ID = 101;
EmployeeName="Tom";员工姓名="汤姆";
ContactAddress.Address1 = "Park Ave"; ContactAddress.Address1 = "公园大道";
ContactAddress.City = "New York"; ContactAddress.City = "纽约";
ContactAddress.State = "NewYork"; ContactAddress.State = "纽约";
ContactAddress.ZipCode = "10002" ContactAddress.ZipCode = "10002"

So in this case, because none of the fields in employeeCopy.ContactAddress have been set, only those fields from the original employee object should be copied across.因此,在这种情况下,由于没有设置employeeCopy.ContactAddress中的任何字段,因此只应复制原始employee object 中的那些字段。

I can not figure out how to write the method:我不知道如何编写方法:
CopyPropertiesTo(object sourceObject, object targetObject)

One way to do this is to simply check each property in the "to" Employee , and if it's null or 0 , assign it the value from the "from" Employee :一种方法是简单地检查“to” Employee中的每个属性,如果它是null0 ,则为其分配来自“from” Employee的值:

/// <summary>
/// Copies values in 'from' to 'to' if they are null in 'to'
/// </summary>
public static void CopyProperties(Employee from, Employee to)
{
    if (from == null) return;
    if (to == null) to = new Employee();

    if (to.EmployeeID == 0) to.EmployeeID = from.EmployeeID;
    if (to.EmployeeName == null) to.EmployeeName = from.EmployeeName;

    if (from.ContactAddress == null) return;
    if (to.ContactAddress == null) to.ContactAddress = new Address();

    if (to.ContactAddress.Address1 == null)
        to.ContactAddress.Address1 = from.ContactAddress.Address1;
    if (to.ContactAddress.City == null)
        to.ContactAddress.City = from.ContactAddress.City;
    if (to.ContactAddress.State == null)
        to.ContactAddress.State = from.ContactAddress.State;
    if (to.ContactAddress.ZipCode == null)
        to.ContactAddress.ZipCode = from.ContactAddress.ZipCode;
}
public static void CopyPropertiesTo(Employee EP1, Employee EP2){
    
    Type eType=typeof(Employee);
    PropertyInfo[] eProps = eType.GetProperties();

    foreach(var p in eProps){
        if(p.PropertyType != typeof(String) && p.PropertyType != typeof(Int32)){
            //Merging Contact Address
            Type cType=p.PropertyType;
            PropertyInfo[] cProps = cType.GetProperties();
            
            foreach(var c in cProps){
                //Check if value is null
                if (String.IsNullOrEmpty((EP2.ContactAddress.GetType().GetProperty(c.Name).GetValue(EP2.ContactAddress) as string))){
                    //Assign Source to Target
                    EP2.ContactAddress.GetType().GetProperty(c.Name).SetValue(EP2.ContactAddress, (EP1.ContactAddress.GetType().GetProperty(c.Name).GetValue(EP1.ContactAddress)));
                }
            }
        }
        else{
            //Check if value is null or empty
            if (String.IsNullOrEmpty((EP2.GetType().GetProperty(p.Name).GetValue(EP2) as string))){
                //Assign Source to Target
                EP2.GetType().GetProperty(p.Name).SetValue(EP2, (EP1.GetType().GetProperty(p.Name).GetValue(EP1)));
            }
        }
    }
}

Not the prettiest, but this should do it and allow you to change the names/amount of properties in the class.不是最漂亮的,但这应该可以让您更改 class 中的属性名称/数量。 I haven't ever actually tried doing it like this so if someone out there has some feedback, I would appreciate it我从来没有真正尝试过这样做,所以如果有人有一些反馈,我将不胜感激

Check out the following links for more info and examples PropertyInfo GetType GetProperty查看以下链接以获取更多信息和示例PropertyInfo GetType GetProperty

Here is my suggestions too if not too late, but mayby helps.如果还不算太晚,这也是我的建议,但也许会有所帮助。

    public class Source
    {
        [DefaultValueAttribute(-1)]
        public int Property { get; set; }

        public int AnotherProperty { get; set; }
    }

    public class Dedstination
    {
        public int Property { get; set; }

        [DefaultValueAttribute(42)]
        public int AnotherProperty { get; set; }
    }

    public void Main()
    {
        var source = new Source { Property = 10, AnotherProperty = 76 };
        var destination = new Dedstination();

        MapValues(source, destination);
    }

    public static void MapValues<TS, TD>(TS source, TD destination)
    {
        var srcPropsWithValues = typeof(TS)
            .GetProperties(BindingFlags.Public | BindingFlags.Instance)
            .ToDictionary(x => x.Name, y => y.GetValue(source));

        var dstProps = typeof(TD)
       .GetProperties(BindingFlags.Public | BindingFlags.Instance)
       .ToDictionary(key => key, value => value.GetCustomAttribute<DefaultValueAttribute>()?.Value
                                       ?? (value.PropertyType.IsValueType
                                       ? Activator.CreateInstance(value.PropertyType, null)
                                       : null));

        foreach (var prop in dstProps)
        {
            var destProperty = prop.Key;

            if (srcPropsWithValues.ContainsKey(destProperty.Name))
            {
                var defaultValue = prop.Value;
                var currentValue = destProperty.GetValue(destination);
                var sourceValue = srcPropsWithValues[destProperty.Name];

                if (currentValue.Equals(defaultValue) && !sourceValue.Equals(defaultValue))
                {
                    destProperty.SetValue(destination, sourceValue);
                }
            }
        }
    }

EDIT: I edited my solution in order to remove the dependency on using DefaultValueAttribute.编辑:我编辑了我的解决方案,以消除对使用 DefaultValueAttribute 的依赖。 Now you can take a default value either from the attributes if specified or the type defaults.现在,您可以从指定的属性或类型默认值中获取默认值。

Previous solution was as follows:以前的解决方案如下:

        // This solution do not needs DefaultValueAttributes 
        var dstProps = typeof(TD)
           .GetProperties(BindingFlags.Public | BindingFlags.Instance)
           .ToDictionary(x => x, x => x.PropertyType.IsValueType ? Activator.CreateInstance(x.PropertyType, null) : null);

        // This solution needs DefaultValueAttributes 
        var dstProps = typeof(TD)
           .GetProperties(BindingFlags.Public | BindingFlags.Instance)
           .ToDictionary(x => x, x => x.GetCustomAttribute<DefaultValueAttribute>()?.Value ?? null);

Make your changes to the new instance after the copy completes and/or implement ICloneable interface.在复制完成和/或实现 ICloneable 接口后对新实例进行更改。 https://docs.microsoft.com/en-us/dotnet/api/system.icloneable?view=netcore-3.1 https://docs.microsoft.com/en-us/dotnet/api/system.icloneable?view=netcore-3.1

Deep cloning can be achieved easily through serialization, however to only copy across non-null fields needs more conditional logic, In this case I call this a Coalesce so I've named my Method CoalesceTo .深度克隆可以通过序列化轻松实现,但是仅跨非空字段复制需要更多条件逻辑,在这种情况下,我将其称为Coalesce ,因此我将我的方法命名为CoalesceTo You could refactor this into an extension method if you wanted to, but I wouldn't recommend it, instead put this inside a static helper class.如果您愿意,您可以将其重构为扩展方法,但我不推荐它,而是将其放在 static 助手 class 中。 As useful as this might be, I don't encourage it as your "goto" for a production business runtime.尽管这可能很有用,但我不鼓励将其作为生产业务运行时的“goto”。

Using Reflection for these types of solutions is usually the most inefficient mechanism, but it gives us a lot of flexibility and is great for mocking, prototyping and quick unit test expressions.对这些类型的解决方案使用反射通常是效率最低的机制,但它为我们提供了很大的灵活性,并且非常适合 mocking、原型设计和快速单元测试表达式。

  • Although not in this example, it would be easy to add in checks to exclude [Obsolete] properties for advanced scenarios尽管不在此示例中,但可以轻松添加检查以排除高级场景的[Obsolete]属性

The following example uses Property Name comparison, so you don't have to pass in objects of the same type.以下示例使用属性名称比较,因此您不必传入相同类型的对象。 Notice that IsNull and IsValueType methods have been created to encapsulate those concepts, simplifying tweaks you might want to make to this method.请注意,已创建IsNullIsValueType方法来封装这些概念,从而简化您可能希望对此方法进行的调整。

  • This method also checks that properties can be read/written before proceeding, which allows us to support readonly properties on the source object, and of course we don't try to write to readonly properties.此方法还在继续之前检查是否可以读取/写入属性,这允许我们在源 object 上支持只读属性,当然我们不会尝试写入只读属性。
  • The final value parse and write is wrapped in a try catch statement that is suppressing any errors, It takes a bit of tweaking to get code like this to work universally, but it should work fine for simple type definitions.解析和写入的最终值包含在抑制任何错误的 try catch 语句中,需要进行一些调整才能使这样的代码普遍工作,但对于简单的类型定义应该可以正常工作。
/// <summary>
/// Deep Copy the top level properties from this object only if the corresponding property on the target object IS NULL.
/// </summary>
/// <param name="source">the source object to copy from</param>
/// <param name="target">the target object to update</param>
/// <returns>A reference to the Target instance for chaining, no changes to this instance.</returns>
public static void CoalesceTo(object source, object target, StringComparison propertyComparison = StringComparison.OrdinalIgnoreCase)
{
    var sourceType = source.GetType();
    var targetType = target.GetType();
    var targetProperties = targetType.GetProperties();
    foreach(var sourceProp in sourceType.GetProperties())
    {
        if(sourceProp.CanRead)
        {
            var sourceValue = sourceProp.GetValue(source);

            // Don't copy across nulls or defaults
            if (!IsNull(sourceValue, sourceProp.PropertyType))
            {
                var targetProp = targetProperties.FirstOrDefault(x => x.Name.Equals(sourceProp.Name, propertyComparison));
                if (targetProp != null && targetProp.CanWrite)
                {
                    if (!targetProp.CanRead)
                        continue; // special case, if we cannot verify the destination, assume it has a value.
                    else if (targetProp.PropertyType.IsArray || targetProp.PropertyType.IsGenericType // It is ICollection<T> or IEnumerable<T>
                                                                && targetProp.PropertyType.GenericTypeArguments.Any()
                                                                && targetProp.PropertyType.GetGenericTypeDefinition() != typeof(Nullable<>) // because that will also resolve GetElementType!
                            )
                        continue; // special case, skip arrays and collections...
                    else
                    {
                        // You can do better than this, for now if conversion fails, just skip it
                        try
                        {
                            var existingValue = targetProp.GetValue(target);
                            if (IsValueType(targetProp.PropertyType))
                            {
                                // check that the destination is NOT already set.
                                if (IsNull(existingValue, targetProp.PropertyType))
                                {
                                    // we do not overwrite a non-null destination value
                                    object targetValue = sourceValue;
                                    if (!targetProp.PropertyType.IsAssignableFrom(sourceProp.PropertyType))
                                    {
                                        // TODO: handle specific types that don't go across.... or try some brute force type conversions if neccessary
                                        if (targetProp.PropertyType == typeof(string))
                                            targetValue = targetValue.ToString();
                                        else 
                                            targetValue = Convert.ChangeType(targetValue, targetProp.PropertyType);
                                    }

                                    targetProp.SetValue(target, targetValue);
                                }
                            }
                            else if (!IsValueType(sourceProp.PropertyType))
                            {
                                // deep clone
                                if (existingValue == null)
                                    existingValue = Activator.CreateInstance(targetProp.PropertyType);

                                CoalesceTo(sourceValue, existingValue);
                            }
                        }
                        catch (Exception)
                        {
                            // suppress exceptions, don't set a field that we can't set
                        }

                    }
                }
            }
        }
    }
}

/// <summary>
/// Check if a boxed value is null or not
/// </summary>
/// <remarks>
/// Evaluate your own logic or definition of null in here.
/// </remarks>
/// <param name="value">Value to inspect</param>
/// <param name="valueType">Type of the value, pass it in if you have it, otherwise it will be resolved through reflection</param>
/// <returns>True if the value is null or primitive default, otherwise False</returns>
public static bool IsNull(object value, Type valueType = null)
{
    if (value is null)
        return true;

    if (valueType == null) valueType = value.GetType();

    if (valueType.IsPrimitive || valueType.IsEnum || valueType.IsValueType)
    {
        // Handle nullable types like float? or Nullable<Int>
        if (valueType.IsGenericType)
            return value is null;
        else
            return Activator.CreateInstance(valueType).Equals(value);
    }

    // treat empty string as null!
    if (value is string s)
        return String.IsNullOrWhiteSpace(s);

    return false;
}
/// <summary>
/// Check if a type should be copied by value or if it is a complexe type that should be deep cloned
/// </summary>
/// <remarks>
/// Evaluate your own logic or definition of Object vs Value/Primitive here.
/// </remarks>
/// <param name="valueType">Type of the value to check</param>
/// <returns>True if values of this type can be straight copied, false if they should be deep cloned</returns>
public static bool IsValueType(Type valueType)
{
    // TODO: any specific business types that you want to treat as value types?

    // Standard .Net Types that can be treated as value types
    if (valueType.IsPrimitive || valueType.IsEnum || valueType.IsValueType || valueType == typeof(string))
        return true;

    // Support Nullable Types as Value types (Type.IsValueType) should deal with this, but just in case
    if (valueType.HasElementType // It is array/enumerable/nullable
        && valueType.IsGenericType && valueType.GetGenericTypeDefinition() == typeof(Nullable<>))
        return true;


    return false;
}

Because we are using reflection here, we cant take advantage of optimisations that Generics could offer us.因为我们在这里使用反射,所以我们无法利用Generics可以为我们提供的优化。 If you wanted to adapt this to a production environment, consider using T4 templates to script out a Generic typed version of this logic as extension methods to your business types.如果您想将其应用于生产环境,请考虑使用 T4 模板来编写此逻辑的通用类型版本作为您的业务类型的扩展方法。

Deep Cloning -深度克隆 -

You'll notice I specifically skip arrays and other IEnumerable structures... There's a whole can of worms in supporting them, it might be better to not let the one method attempt a Deep copy, so take the nested call to CoalesceTo out, then call the clone method on each object in the tree.你会注意到我特别跳过了 arrays 和其他 IEnumerable 结构......有一大堆蠕虫在支持它们,最好不要让一种方法尝试深度复制,所以把嵌套调用CoalesceTo拿出来,然后在树中的每个 object 上调用 clone 方法。

The problem with arrays/collections/lists is that before you could clone, you would need to identify a way to synchronise the collection in the source with the collection in the target, you could make a convention based on an Id field or some kind of attribute like [KeyAttribute] but that sort of implementation needs to be highly specific to your business logic and is outside of the scope of this already monstrous post;)数组/集合/列表的问题在于,在克隆之前,您需要确定一种将源中的集合与目标中的集合同步的方法,您可以根据 Id 字段或某种形式进行约定像[KeyAttribute]这样的属性,但这种实现需要高度特定于您的业务逻辑,并且不在这个已经很可怕的帖子的 scope 之外;)

Types like Decimal and DateTime are problematic in these types of scenarios, they should not be compared to null, instead we have to compare them to their default type states, again we can't use the generic default operator or value in this case because the type can only be resolved at runtime.DecimalDateTime这样的类型在这些类型的场景中是有问题的,它们不应该与 null 进行比较,而是我们必须将它们与它们的默认类型状态进行比较,同样我们不能在这种情况下使用通用的default运算符或值,因为类型只能在运行时解析。

So I've changed your classes to include an example of how DateTimeOffset is handled by this logic:因此,我更改了您的类,以包含一个示例,说明此逻辑如何处理 DateTimeOffset:

public class Employee
{
    public int EmployeeID { get; set; }
    public string EmployeeName { get; set; }
    public DateTimeOffset Date { get; set; }
    public float? Capacity { get; set; }
    Nullable<int> MaxShift { get; set; }
    public Address ContactAddress { get; set; }
}

public class Address
{
    public string Address1 { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    public string ZipCode { get; set; }
}

public static  void TestMethod1()
{
    Employee employee = new Employee();
    employee.EmployeeID = 100;
    employee.EmployeeName = "John";
    employee.Capacity = 26.2f;
    employee.MaxShift = 8;
    employee.Date = new DateTime(2020,1,22);
    employee.ContactAddress = new Address();
    employee.ContactAddress.Address1 = "Park Ave";
    employee.ContactAddress.City = "New York";
    employee.ContactAddress.State = "NewYork";
    employee.ContactAddress.ZipCode = "10002";

    Employee employeeCopy = new Employee();
    employeeCopy.EmployeeID = 101;
    employeeCopy.EmployeeName = "Tom";
    employeeCopy.ContactAddress = new Address();

    CoalesceTo(employee, employeeCopy);
}

This results in the following object graph:这会产生以下 object 图:

{
  "EmployeeID": 101,
  "EmployeeName": "Tom",
  "Date": "2020-01-22T00:00:00+11:00",
  "Capacity":26.2,
  "MaxShift":8,
  "ContactAddress": {
    "Address1": "Park Ave",
    "City": "New York",
    "State": "NewYork",
    "ZipCode": "10002"
  }
}

Instead of trying to do a deep copy at all, these types of issues are generally easier and less resource intensive if you do a full deep clone first, and then set your values.如果您首先进行完整的深度克隆然后设置您的值,那么这些类型的问题通常会更容易且资源消耗更少,而不是尝试进行深度复制

There are many posts on SO regarding deep clone , my preference is just to use JSON.Net to serialize and then deserialize. SO上有很多关于深度克隆的帖子,我的偏好只是使用 JSON.Net 进行序列化然后反序列化。

 public static T Clone<T>(T value, Newtonsoft.Json.JsonSerializerSettings settings = null) { var objectType = value.GetType(); var cereal = Newtonsoft.Json.JsonConvert.SerializeObject(value, settings); return (T)Newtonsoft.Json.JsonConvert.DeserializeObject(cereal, objectType, settings); }

However this code requires the Newtonsoft.Json nuget package reference.但是,此代码需要Newtonsoft.Json nuget package 参考。

Cloning the object sets all the common/default values first , and then we only modify those properties that we need for this specific test, or code block.克隆 object首先设置所有通用/默认值,然后我们只修改此特定测试或代码块所需的那些属性。

public void TestMethod1()
{
    Employee employee = new Employee();
    employee.EmployeeID = 100;
    employee.EmployeeName = "John";
    employee.ContactAddress = new Address();
    employee.ContactAddress.Address1 = "Park Ave";
    employee.ContactAddress.City = "New York";
    employee.ContactAddress.State = "NewYork";
    employee.ContactAddress.ZipCode = "10002";
 
    // Create a deep clone of employee
    Employee employeeCopy = Clone(employee);

    // set the specific fields that we want to change
    employeeCopy.EmployeeID = 101;
    employeeCopy.EmployeeName = "Tom";

}

Often we can find simpler solutions if we are open to changing our approach, this solution will have the same output as if we had conditionally copied across the property values, but without comparing anything.如果我们愿意改变我们的方法,我们通常可以找到更简单的解决方案,这个解决方案将具有相同的 output,就好像我们有条件地复制了属性值一样,但没有进行任何比较。

If you have other reasons for a conditional copy, referred to in other solutions to this post as a Merge or Coalesce , then my other answer using reflection will do the job, but its not as robust as this one.如果您有条件副本的其他原因,在这篇文章的其他解决方案中称为MergeCoalesce ,那么我使用反射的其他答案将完成这项工作,但它不如这个强大。

[TestClass]
public class UnitTest11
{
    [TestMethod]
    public void TestMethod1()
    {

        Employee employee = new Employee();
        employee.EmployeeID = 100;
        employee.EmployeeName = "John";
        employee.Date = DateTime.Now;
        employee.ContactAddress = new Address();
        employee.ContactAddress.Address1 = "Park Ave";
        employee.ContactAddress.City = "New York";
        employee.ContactAddress.State = "NewYork";
        employee.ContactAddress.ZipCode = "10002";

        Employee employeeCopy = new Employee();
        employeeCopy.EmployeeID = 101;
        employeeCopy.EmployeeName = "Tom";
        employeeCopy.ContactAddress = new Address();
        employeeCopy.ContactAddress.City = "Bei Jing";
        //copy all properties from employee to employeeCopy
        CoalesceTo(employee, employeeCopy);

        Console.ReadLine();
    }

    /// Deep Copy the top level properties from this object only if the corresponding property on the target object IS NULL.
    /// </summary>
    /// <param name="source">the source object to copy from</param>
    /// <param name="target">the target object to update</param>
    /// <returns>A reference to the Target instance for chaining, no changes to this instance.</returns>
    public static void CoalesceTo(object source, object target, StringComparison propertyComparison = StringComparison.OrdinalIgnoreCase)
    {
        var sourceType = source.GetType();
        var targetType = target.GetType();
        var targetProperties = targetType.GetProperties();
        foreach (var sourceProp in sourceType.GetProperties())
        {
            if (sourceProp.CanRead)
            {
                var sourceValue = sourceProp.GetValue(source);

                // Don't copy across nulls or defaults
                if (!IsNull(sourceValue, sourceProp.PropertyType))
                {
                    var targetProp = targetProperties.FirstOrDefault(x => x.Name.Equals(sourceProp.Name, propertyComparison));
                    if (targetProp != null && targetProp.CanWrite)
                    {
                        if (!targetProp.CanRead)
                            continue; // special case, if we cannot verify the destination, assume it has a value.
                        else if (targetProp.PropertyType.IsArray || targetProp.PropertyType.IsGenericType // It is ICollection<T> or IEnumerable<T>
                                                                    && targetProp.PropertyType.GenericTypeArguments.Any()
                                                                    && targetProp.PropertyType.GetGenericTypeDefinition() != typeof(Nullable<>) // because that will also resolve GetElementType!
                                )
                            continue; // special case, skip arrays and collections...
                        else
                        {
                            // You can do better than this, for now if conversion fails, just skip it
                            try
                            {
                                var existingValue = targetProp.GetValue(target);
                                if (IsValueType(targetProp.PropertyType))
                                {
                                    // check that the destination is NOT already set.
                                    if (IsNull(existingValue, targetProp.PropertyType))
                                    {
                                        // we do not overwrite a non-null destination value
                                        object targetValue = sourceValue;
                                        if (!targetProp.PropertyType.IsAssignableFrom(sourceProp.PropertyType))
                                        {
                                            // TODO: handle specific types that don't go across.... or try some brute force type conversions if neccessary
                                            if (targetProp.PropertyType == typeof(string))
                                                targetValue = targetValue.ToString();
                                            else
                                                targetValue = Convert.ChangeType(targetValue, targetProp.PropertyType);
                                        }

                                        targetProp.SetValue(target, targetValue);
                                    }
                                }
                                else if (!IsValueType(sourceProp.PropertyType))
                                {
                                    // deep clone
                                    if (existingValue == null)
                                        existingValue = Activator.CreateInstance(targetProp.PropertyType);

                                    CoalesceTo(sourceValue, existingValue);
                                }
                            }
                            catch (Exception)
                            {
                                // suppress exceptions, don't set a field that we can't set
                            }

                        }
                    }
                }
            }
        }
    }

    /// <summary>
    /// Check if a boxed value is null or not
    /// </summary>
    /// <remarks>
    /// Evaluate your own logic or definition of null in here.
    /// </remarks>
    /// <param name="value">Value to inspect</param>
    /// <param name="valueType">Type of the value, pass it in if you have it, otherwise it will be resolved through reflection</param>
    /// <returns>True if the value is null or primitive default, otherwise False</returns>
    public static bool IsNull(object value, Type valueType = null)
    {
        if (value is null)
            return true;

        if (valueType == null) valueType = value.GetType();

        if (valueType.IsPrimitive || valueType.IsEnum || valueType.IsValueType)
            return value.Equals(Activator.CreateInstance(valueType));

        // treat empty string as null!
        if (value is string s)
            return String.IsNullOrWhiteSpace(s);

        return false;
    }
    /// <summary>
    /// Check if a type should be copied by value or if it is a complexe type that should be deep cloned
    /// </summary>
    /// <remarks>
    /// Evaluate your own logic or definition of Object vs Value/Primitive here.
    /// </remarks>
    /// <param name="valueType">Type of the value to check</param>
    /// <returns>True if values of this type can be straight copied, false if they should be deep cloned</returns>
    public static bool IsValueType(Type valueType)
    {
        // TODO: any specific business types that you want to treat as value types?

        // Standard .Net Types that can be treated as value types
        if (valueType.IsPrimitive || valueType.IsEnum || valueType.IsValueType || valueType == typeof(string))
            return true;

        // Support Nullable Types as Value types (Type.IsValueType) should deal with this, but just in case
        if (valueType.HasElementType // It is array/enumerable/nullable
            && valueType.IsGenericType && valueType.GetGenericTypeDefinition() == typeof(Nullable<>))
            return true;


        return false;
    }
}


public class Employee
{
    public int EmployeeID { get; set; }
    public string EmployeeName { get; set; }
    public DateTimeOffset Date { get; set; }
    public float? check { get; set; }
    public Address ContactAddress { get; set; }
}

public class Address
{
    public string Address1 { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    public string ZipCode { get; set; }
}

Thank you very much for every one,especially for @Chris Schaller I post the code above非常感谢大家,尤其是@Chris Schaller,我在上面发布了代码

private Employee Check(Employee employee,Employee employeeCopy)
        {
if (employeeCopy.EmployeeID==0 && employee.EmployeeID !=0)
  {
     employeeCopy.EmployeeID = employee.EmployeeID;
  }
if (employeeCopy.EmployeeName == null && employee.EmployeeName != null)
  {
     employeeCopy.EmployeeName = employee.EmployeeName;
  }
if (employeeCopy.ContactAddress == null)
{
if (employeeCopy.ContactAddress.Address1 == null && employee.ContactAddress.Address1 != null)
  {
     employeeCopy.ContactAddress.Address1 = employee.ContactAddress.Address1;
  }
if (employeeCopy.ContactAddress.City == null && employee.ContactAddress.City != null)
 {
     employeeCopy.ContactAddress.City = employee.ContactAddress.City;
 }
if (employeeCopy.ContactAddress.State == null && employee.ContactAddress.State != null)
 {
     employeeCopy.ContactAddress.State = employee.ContactAddress.State;
 }
if (employeeCopy.ContactAddress.ZipCode == null && employee.ContactAddress.ZipCode != null)
 {
    employeeCopy.ContactAddress.ZipCode = employee.ContactAddress.ZipCode;
 }
}
            return employeeCopy;

}

Is this what you are looking for?这是你想要的?

暂无
暂无

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

相关问题 相同的变量名称 - 2个不同的类 - 如何将值从一个复制到另一个 - 反射 - C# - Same Variable Names - 2 Different Classes - How To Copy Values From One To Another - Reflection - C# 将访问控制属性从一个文件复制到另一个 C# - Copy access control properties from one file to another C# 如何将一个列表复制到另一个具有 object 和 C# 附加属性的列表? (没有foreach) - How do I copy one list to another that has an object with additional properties in C# ? (without a foreach) C#列表:如何将元素从一个列表复制到另一个列表,但仅复制某些属性 - C# Lists: How to copy elements from one list to another, but only certain properties 将值从一个对象复制到另一个(不同类型) - Copy values from one object to another (different type) 如何将属性从一个 .net 对象复制到另一个 - How to copy properties from one .net object to another 在C#中将值从一个businesobject复制到另一个而没有循环 - Copy values from one businesobject to another without loop in c# 如何使用LINQ C#将几个属性的值从一个列表更改为另一个: - How to change values of few properties from one list to another using LINQ C#: 如何在C#中设置另一个列表的列表属性 - How to set properties of a list from another different list in C# C#属性以及如何从另一个函数/类访问它们的值? - C# properties and how to access their values from another function/class?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM