2015-02-25 3 views
5

Я работаю над проектом по созданию PDF-форм с использованием PDFView4Net. Хотя библиотека в целом хороша, создатель форм примитивен и не имеет базовых функций (таких как копирование/вставка, выравнивание, форматирование и т. Д.) При работе с полями формы (т. Е. Текстовыми полями, флажками и т. Д.).Глубокая копия сложных сторонних объектов/классов

Проблема: Я расширяющая функциональность для полевых объектов и получать споткнулся на копирование/вставка. Для этого мне нужна глубокая копия объекта без каких-либо ссылок на оригинал. Я отправил по электронной почте поставщику, запросив информацию об их рекомендуемом методе копирования этих объектов, на который они ответили, что мне нужно сделать копию каждого свойства вручную вручную ... бьет головой на стол. Это большие классы с несколькими встроенными классами в качестве свойств, а также элементы пользовательского интерфейса.

Вопрос: Существуют ли какие-либо хорошие методы, которые там выполняют глубокую копию для сложных объектов, которые не требуют сериализации, не требует доступа или изменений к классам источника и не требуют конструктор по умолчанию?

То, что я пробовал/обзор: Я исследовал различные способы, чтобы сделать глубокую копию объекта и отбрасываю их один за другим:

  • вручную, собственности кропотливой недвижимости: I попытался сделать это с первым из 7 объектов поля (PDFTextBoxField), но он быстро вышел из-под контроля со свойствами множества, которые также являются различными типами классов. В конце концов, у меня все еще оставались ссылки на исходный объект, где была создана мелкая копия вместо глубокой копии, как предполагалось.
  • Сериализация: классы не помечены как Serializable, и поставщик не изменит это. Я попросил их, и они сказали «нет».
  • ICloneable: должен быть реализован поставщиком.
  • AutoMapper: Кажется, это копирование данных из одного или нескольких типов объектов в другой тип объекта. Объекты, с которыми я работаю, - это один и тот же тип. Хотя я не против использования этого, если это лучшее решение.
  • Emit Mapper: Этот проект, похоже, был оставлен.
  • MemberwiseClone: ​​Неглубокая копия, а не глубокая копия, которую я ищу, хотя это предлагается на тонне других сообщений, когда вопросник запрашивает глубокую копию.
  • Value Injecter: Я реализовал FastDeepCloneInjection от ValueInjecter на CodePlex, но большинство классов, которые должны быть введены, не имеют конструктора параметров 0, который требуется при создании нового экземпляра для копии. ValueInjecter не позволяет пропускать определенные свойства, или я просто пропустил бы элементы без конструктора по умолчанию и оставил бы их установленными в null (по умолчанию). Я сразу наткнулся на это с самого первого класса. Чтобы попытаться обойти проблему, я создал класс оболочки, унаследованный от оригинала, и отбросил оригинал в оболочку (и наоборот), но я не думаю, что это хорошее решение.

Редактировать: Я действительно не чувствую, что этот вопрос является дубликатом. Я широко искал решение, включая сообщение, помеченное как дубликат/оригинал, и не смог найти удовлетворительное разрешение. Как уже было сказано, у меня нет доступа к изменению классов, которые мне нужно скопировать.Это скидки DataContractSerializer, BinaryFormatter и любой другой тип сериализации. Это также уменьшает примеры отражения, которые я видел с помощью Activator.CreateInstance, так как около 95% классов, которые мне нужно скопировать, не имеют конструктора, который принимает 0 аргументов. Это та же проблема, с которой я столкнулся с использованием ValueInjecter. Это также скидки, использующие ICloneable.

+1

Как насчет хорошей [отражения и рекурсии] (HTTP: // StackOverflow .com/а/13199808/2589202)? – paqogomez

+0

Чтобы клонировать объект с помощью любой сериализации вручную (отражение и рекурсия, как предлагается), вы должны начать с создания простого экземпляра * без * вызова конструктора через 'FormatterServices.GetUninitializedObject (type)'. –

+0

Возможно, что-то вроде: https: //code.msdn.microsoft.com/CSDeepCloneObject-8a53311e или http://www.codeproject.com/Articles/38270/Deep-copy-of-objects-in-C или http://thomashapp.com/node/106 –

ответ

2

Я бы использовал AutoMapper для этого. Рассмотрим следующее определение класса: (обратите внимание на частный CTOR)

public class Parent 
{ 
    public string Field1 { get; set; } 
    public Level1 Level1 { get; set; } 
    public static Parent GetInstance() 
    { 
     return new Parent() { Field1 = "1", Level1 = new Level1 { Field2 = "2", Level2 = new Level2() { Field3 = "3"}}}; 
    } 
    private Parent() {    } 
} 

public class Level1 
{ 
    public string Field2 { get; set; } 
    public Level2 Level2 { get; set; } 
} 

public class Level2 
{ 
    public string Field3 { get; set; } 
} 

Вы можете настроить AutoMapper для глубокого клона в соответствии с требованиями:

[TestMethod] 
public void DeepCloneParent() 
{ 
    Mapper.CreateMap<Parent, Parent>(); 
    Mapper.CreateMap<Level1, Level1>(); 
    Mapper.CreateMap<Level2, Level2>(); 
    var parent = Parent.GetInstance(); 

    var copy = Mapper.Map<Parent, Parent>(parent); 

    Assert.IsFalse(copy == parent);//diff object 
    Assert.IsFalse(copy.Level1 == parent.Level1);//diff object 
    Assert.IsFalse(copy.Level1.Level2 == parent.Level1.Level2);//diff object 
    Assert.AreEqual("1", copy.Field1); 
    Assert.AreEqual("2", copy.Level1.Field2); 
    Assert.AreEqual("3", copy.Level1.Level2.Field3); 
} 
+0

Спасибо за рекомендацию. Наконец, я смог получить первое из 7 полей для успешной копирования с помощью AutoMapper. Я все еще не уверен, что это лучшее решение. Библиотека классов PDFView4Net содержит 266 классов. Он потребовал более 400 строк кода, чтобы получить этот первый экземпляр без ошибок. Тем не менее, я думаю, это лучше, чем делать все вручную. – mslissap

+0

@mslissap почему так много строк ??? (сколько классов было вовлечено в этот первый экземпляр?) – wal

+0

116 классов для 1-го экземпляра. Поставщик использует много «мини» классов для наследования (свойство C, наследует от B, наследует от A, наследует от базы). Для одного свойства может потребоваться 4-5 классов. Это был самый простой из 7 объектов, которые мне нужно скопировать, хотя другие используют многие из тех же «базовых» классов для наследования. Для многих из них мне пришлось создать ResolutionContext для CreateMap.ConstructUsing, поскольку не было конструктора без параметров (я их по умолчанию), затем создайте действие AfterMap, чтобы получить реальное значение из источника и в пункт назначения. – mslissap

Смежные вопросы