Vamos a um código para clonar objetos sem utilizar serialização (o que cria um monte de problemas) e de quebra ainda ganha muito em performance.
Infelizmente esse é um de meus poucos posts feitos somente em C# (peço desculpa aos programadores em VB, mas, esse código foi hardcore para fazer).
1-) Classe de Serialização Tipada
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
namespace AdvancedClone
{
/// <summary>
/// Generic Clone Class
/// </summary>
public sealed class TypedCloneStrategy<T>
{
/// <summary>
/// Cache para os Campos do(s) Tipo(s) Utilizado(s)
/// </summary>
private readonly Dictionary<Type, Dictionary<string, FieldInfo>> _FieldsCache =
new Dictionary<Type, Dictionary<string, FieldInfo>>();
/// <summary>
/// Clona um Objeto
/// </summary>
/// <param name="target"></param>
/// <returns></returns>
public T Clone(T target)
{
// Create Objetos
object resultSet;
Dictionary<string, FieldInfo> typeFields;
ConstructorInfo typeLessConstructor;
Type isICloneType;
ICloneable iClone;
Type isIEnumerableType;
IEnumerable iEnum;
Type isIListType;
Type isIDicType;
IList list;
IDictionary dic;
// Retreave Default TypeLess Constructor (Public or NonPublic)
typeLessConstructor =
target.GetType().GetConstructor(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance,
null, new Type[] {}, null);
// Initialize ResultSet Object
resultSet = typeLessConstructor.Invoke(null);
// Retreave All Type Field's
typeFields = GetFields(target.GetType());
// Looping on Fields
foreach (KeyValuePair<string, FieldInfo> info in typeFields)
{
//Query if the fiels support the ICloneable Interface
isICloneType = info.Value.FieldType.GetInterface("ICloneable", false);
// Supports ICloneable Interface, Then, Use Direct Clone Approach
if (isICloneType != null)
{
// Getting the ICloneable interface from the object.
iClone = (ICloneable) info.Value.GetValue(target);
// If Value Are NotNull
if (iClone != null)
{
object clonedObject = iClone.Clone();
//We use the clone method to set the new value to the field.
info.Value.SetValue(resultSet, clonedObject);
}
}
else // Property Not Support ICloneable Interface
{
info.Value.SetValue(resultSet, info.Value.GetValue(target));
}
// Check If Object Supports a IEnumerable interface so if it does we need to enumerate all its items and check if they support the ICloneable interface.
isIEnumerableType = info.Value.FieldType.GetInterface("IEnumerable", false);
// Check Result for IEnumerable Interface Search
if (isIEnumerableType != null)
{
// Get the IEnumerable interface from the field.
iEnum = (IEnumerable) info.Value.GetValue(target);
// Get The IList and the IDictionary Interfaces to iterate on collections.
isIListType = info.Value.FieldType.GetInterface("IList", false);
isIDicType = info.Value.FieldType.GetInterface("IDictionary", false);
// If Collection Supports a IList Interface
if (isIListType != null)
{
// Getting the IList interface.
list = (IList) info.Value.GetValue(resultSet);
// Looping on IEnumerable Itens
if (list != null)
{
foreach (object obj in iEnum)
{
// Checking to see if the current item support the ICloneable interface.
isICloneType = obj.GetType().GetInterface( "ICloneable", false);
// Supports a Clone Type
if (isICloneType != null)
{
// If it does support the ICloneable interface,
// we use it to set the clone of
// the object in the list.
ICloneable clone = (ICloneable) obj;
list.Add(clone.Clone());
}
}
}
}
else if (isIDicType != null) // IDictionary Interface
{
// Getting the dictionary interface.
dic = (IDictionary) info.Value.GetValue(resultSet);
// Looping on
if (iEnum != null)
{
foreach (DictionaryEntry de in iEnum)
{
// Checking to see if the item support the ICloneable interface.
isICloneType = de.Value.GetType().GetInterface( "ICloneable", false);
if (isICloneType != null)
{
ICloneable clone = (ICloneable) de.Value;
dic[de.Key] = clone.Clone();
}
}
}
}
}
}
// Returns a Clonned ResultSet Object
return (T) resultSet;
}
/// <summary>
/// Recupera os Fields de um Objeto pelo Tipo
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
private Dictionary<string, FieldInfo> GetFields(Type type)
{
// Verifica no Cache
if (!_FieldsCache.ContainsKey(type))
{
lock (typeof (TypedCloneStrategy<T>))
{
if (!_FieldsCache.ContainsKey(type))
{
_FieldsCache.Add(type, GetAllFields(type));
}
}
}
// Retorna do Cache
return _FieldsCache[type];
}
/// <summary>
/// Método para Extrair os Fields de um Determinado Objeto
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
private Dictionary<string, FieldInfo> GetAllFields(Type type)
{
// Cria Objeto
Dictionary<string, FieldInfo> fields = new Dictionary<string, FieldInfo>();
foreach (FieldInfo info in type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.FlattenHierarchy))
{
if (!fields.ContainsKey(info.Name))
{
fields.Add(info.Name, info);
}
}
if (type.BaseType != null)
{
Dictionary<string, FieldInfo> baseFields = GetAllFields(type.BaseType);
foreach (KeyValuePair<string, FieldInfo> pair in baseFields)
{
if (!fields.ContainsKey(pair.Key))
{
fields.Add(pair.Key, pair.Value);
}
}
}
return fields;
}
}
}
2-) Usando a Classe
Para usar a classe, precisamos de um objeto de origem e uma variável de destino.
MeuObjetoDestino x = new AdvancedClone.TypedCloneStrategy<TipoDoMeuObjeto>().Clone(meuObjetoOrigem);
Posts Relacionados:
- Calculando CRC de Strings (Texto), Array’s e Arquivos
- Manipulando Arquivos e Diretórios no .NET
- Convertendo Caminhos Absolutos e URL’s Absolutas para Caminhos Relativos e URL’s Relativas
- Convertendo String Delimitada por Tamanho (Trancode) em Array
- Compressão de (Compactar) Dados
- Algoritmo para Validação de CPF
- Ordenação de Listas (Coleções)



1 Reposta to “Clonando Objetos (.Clone()) sem Serialização”
Carlos
1 year ago
Muito bom o artigo hein cara…
Parabéns…! :-)