Как глубоко скопировать между объектами различных типов в C#.NET

Вы также можете получить значения, как показано ниже,

> a = a.split('_')
> a[0..-2].join('_')
# => "a_b_c_d" 
> a[-1]
# => "e" 
10
задан Jon Simpson 20 February 2009 в 11:08
поделиться

7 ответов

Как альтернатива использованию отражения каждый раз, Вы могли создать класс помощника, который динамично создает методы копии с помощью Отражения. Испустите - это означало бы, что Вы только поражали производительность в запуск. Это может дать Вам комбинацию гибкости и производительности, в которой Вы нуждаетесь.

Как Отражение. Испустите является довольно неуклюжим, я предложил бы проверить это дополнение Отражателя, которое является блестящим для создания этого вида кода.

6
ответ дан 3 December 2019 в 20:44
поделиться

Какая версия.NET - это?

Для мелкой копии:

В 3,5, можно предварительно скомпилировать Expression сделать это. В 2,0, можно использовать HyperDescriptor очень легко сделать то же. Оба значительно превзойдут отражение по характеристикам.

Существует предконсервированная реализация Expression подход в MiscUtil - PropertyCopy:

DestType clone = PropertyCopy<DestType>.CopyFrom(original);

(закончите мелкий),

BinaryFormatter (в вопросе) не является опцией здесь - он просто не будет работать, так как исходные и целевые типы отличаются. Если бы данные являются базирующимся контрактом, XmlSerializer или DataContractSerializer работали бы, если бы все имена контракта соответствуют, но две (мелких) опции выше были бы намного более быстрыми, если они возможны.

Также - если Ваши типы отмечены с общими атрибутами сериализации (XmlType или DataContract), затем protobuf-сеть может (в некоторых случаях) сделать глубокую копию / тип изменения для Вас:

DestType clone = Serializer.ChangeType<OriginalType, DestType>(original);

Но это зависит от типов, имеющих очень похожие схемы (на самом деле, это не использует имена, это использует явный "Порядок" и т.д. на атрибуты),

4
ответ дан 3 December 2019 в 20:44
поделиться

Если скорость является проблемой, Вы могли бы вывести отражательный процесс из эксплуатации и сгенерировать код для отображения общей собственности. Вы могли сделать это во времени выполнения с помощью Легкой Генерации кода или абсолютно офлайн путем создания кода C# для компиляции.

1
ответ дан 3 December 2019 в 20:44
поделиться

Если скорость является проблемой, необходимо реализовать методы клона в самих методах.

0
ответ дан 3 December 2019 в 20:44
поделиться

Вот решение, которое я создал:

     /// <summary>
        /// Copies the data of one object to another. The target object gets properties of the first. 
        /// Any matching properties (by name) are written to the target.
        /// </summary>
        /// <param name="source">The source object to copy from</param>
        /// <param name="target">The target object to copy to</param>
        public static void CopyObjectData(object source, object target)
        {
            CopyObjectData(source, target, String.Empty, BindingFlags.Public | BindingFlags.Instance);
        }

        /// <summary>
        /// Copies the data of one object to another. The target object gets properties of the first. 
        /// Any matching properties (by name) are written to the target.
        /// </summary>
        /// <param name="source">The source object to copy from</param>
        /// <param name="target">The target object to copy to</param>
        /// <param name="excludedProperties">A comma delimited list of properties that should not be copied</param>
        /// <param name="memberAccess">Reflection binding access</param>
        public static void CopyObjectData(object source, object target, string excludedProperties, BindingFlags memberAccess)
        {
            string[] excluded = null;
            if (!string.IsNullOrEmpty(excludedProperties))
            {
                excluded = excludedProperties.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries);
            }

            MemberInfo[] miT = target.GetType().GetMembers(memberAccess);
            foreach (MemberInfo Field in miT)
            {
                string name = Field.Name;

                // Skip over excluded properties
                if (string.IsNullOrEmpty(excludedProperties) == false
                    && excluded.Contains(name))
                {
                    continue;
                }


                if (Field.MemberType == MemberTypes.Field)
                {
                    FieldInfo sourcefield = source.GetType().GetField(name);
                    if (sourcefield == null) { continue; }

                    object SourceValue = sourcefield.GetValue(source);
                    ((FieldInfo)Field).SetValue(target, SourceValue);
                }
                else if (Field.MemberType == MemberTypes.Property)
                {
                    PropertyInfo piTarget = Field as PropertyInfo;
                    PropertyInfo sourceField = source.GetType().GetProperty(name, memberAccess);
                    if (sourceField == null) { continue; }

                    if (piTarget.CanWrite && sourceField.CanRead)
                    {
                        object targetValue = piTarget.GetValue(target, null);
                        object sourceValue = sourceField.GetValue(source, null);

                        if (sourceValue == null) { continue; }

                        if (sourceField.PropertyType.IsArray
                            && piTarget.PropertyType.IsArray
                            && sourceValue != null ) 
                        {
                            CopyArray(source, target, memberAccess, piTarget, sourceField, sourceValue);
                        }
                        else
                        {
                            CopySingleData(source, target, memberAccess, piTarget, sourceField, targetValue, sourceValue);
                        }
                    }
                }
            }
        }

        private static void CopySingleData(object source, object target, BindingFlags memberAccess, PropertyInfo piTarget, PropertyInfo sourceField, object targetValue, object sourceValue)
        {
            //instantiate target if needed
            if (targetValue == null
                && piTarget.PropertyType.IsValueType == false
                && piTarget.PropertyType != typeof(string))
            {
                if (piTarget.PropertyType.IsArray)
                {
                    targetValue = Activator.CreateInstance(piTarget.PropertyType.GetElementType());
                }
                else
                {
                    targetValue = Activator.CreateInstance(piTarget.PropertyType);
                }
            }

            if (piTarget.PropertyType.IsValueType == false
                && piTarget.PropertyType != typeof(string))
            {
                CopyObjectData(sourceValue, targetValue, "", memberAccess);
                piTarget.SetValue(target, targetValue, null);
            }
            else
            {
                if (piTarget.PropertyType.FullName == sourceField.PropertyType.FullName)
                {
                    object tempSourceValue = sourceField.GetValue(source, null);
                    piTarget.SetValue(target, tempSourceValue, null);
                }
                else
                {
                    CopyObjectData(piTarget, target, "", memberAccess);
                }
            }
        }

        private static void CopyArray(object source, object target, BindingFlags memberAccess, PropertyInfo piTarget, PropertyInfo sourceField, object sourceValue)
        {
            int sourceLength = (int)sourceValue.GetType().InvokeMember("Length", BindingFlags.GetProperty, null, sourceValue, null);
            Array targetArray = Array.CreateInstance(piTarget.PropertyType.GetElementType(), sourceLength);
            Array array = (Array)sourceField.GetValue(source, null);

            for (int i = 0; i < array.Length; i++)
            {
                object o = array.GetValue(i);
                object tempTarget = Activator.CreateInstance(piTarget.PropertyType.GetElementType());
                CopyObjectData(o, tempTarget, "", memberAccess);
                targetArray.SetValue(tempTarget, i);
            }
            piTarget.SetValue(target, targetArray, null);
        }
2
ответ дан 3 December 2019 в 20:44
поделиться

Возможно, вы захотите взглянуть на AutoMapper , библиотеку, которая специализируется на копировании значений между объектами. Он использует соглашение, а не конфигурацию, поэтому, если свойства действительно имеют одинаковые имена exaxt, он сделает почти всю работу за вас.

4
ответ дан 3 December 2019 в 20:44
поделиться

Если вы контролируете инстанцирование целевого объекта, попробуйте использовать JavaScriptSerializer. Он не выдает никакой информации о типе.

new JavaScriptSerializer().Serialize(new NamespaceA.Person{Id = 1, Name = "A"})

возвращает

{Id: 1, Name: "A"}

Из него можно десериализовать любой класс с теми же именами свойств.

1
ответ дан 3 December 2019 в 20:44
поделиться
Другие вопросы по тегам:

Похожие вопросы: