 |
|
 |
I use this code for making a clone of my objects but `I got an exception when i run it for my code The eception is An unhandled exception of type 'System.StackOverflowException' occurred in mscorlib.dll what I have to do ? please help me
|
|
|
|
 |
|
 |
Hi,
This piece of code did'nt really create new objects with the enumerable types, I got references and the IEnum modified error while browsing through it.
I changed it a little : it does'nt clone Lists anymore , but rather populate them with cloned objects.
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Reflection; using System.Collections;
namespace YourNameSpace { ///
/// BaseObject class is an abstract class for you to derive from.
/// Every class that will be dirived from this class will support the
/// Clone method automaticly.
/// The class implements the interface ICloneable and there
/// for every object that will be derived
/// from this object will support the ICloneable interface as well.
///
public abstract class ObjetClonable : ICloneable { ///
/// Clone the object, and returning a reference to a cloned object.
///
/// Reference to the new cloned
/// object.
public object Clone() { //First we create an instance of this specific type.
object newObject = Activator.CreateInstance(this.GetType());
//We get the array of properties for the new type instance.
//FieldInfo[] properties = newObject.GetType().GetFields();
PropertyInfo[] properties = newObject.GetType().GetProperties();
int i = 0;
foreach (PropertyInfo prop in this.GetType().GetProperties()) { //We query if the properties support the ICloneable interface.
Type ICloneType = prop.PropertyType. GetInterface("ICloneable", true);
//We check if the object support the IEnumerable interface, so if it does we need to enumerate all its items and check if they support the ICloneable interface.
Type IEnumType = prop.PropertyType.GetInterface("IList", true);
if (ICloneType != null && (prop.PropertyType != typeof(System.String))) { //Getting the ICloneable interface from the object. //We use the clone method to set the new value to the field.
if (properties[i].CanWrite) { ICloneable IClone = (ICloneable)prop.GetValue(this, null); properties[i].SetValue(newObject, IClone.Clone(), null); } } else { // If the field doesn't support the ICloneable interface then just set it If it is'nt Enumerable, if it is : we ll only later add objects to it !
if (properties[i].CanWrite && (IEnumType == null)) { properties[i].SetValue(newObject, prop.GetValue(this,null),null); } }
if (IEnumType != null) // That properterty isn't cloned : it is created and populated with cloned objects. { //Get the IEnumerable interface from the field.
IEnumerable IEnum = (IEnumerable)prop.GetValue(this,null);
//This version support the IList
Type IListType = properties[i].PropertyType.GetInterface ("IList", true);
if (IListType != null) { //Getting the IList interface.
IList list = (IList)properties[i].GetValue(newObject,null);
int j = 0; foreach (object obj in IEnum) { //Checking to see if the current item
//support the ICloneable interface.
ICloneType = obj.GetType(). GetInterface("ICloneable", true);
if (ICloneType != 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()); }
j++; } } } i++; } return newObject; } }
}
|
|
|
|
 |
|
 |
Hi all, I have a problem for clone the Dictionary<t,> object. Can U help me how to modify the code.
The follow code is getting the IDictionary interface.
IDictionary dic = (IDictionary)fields[i].GetValue(newObject); j = 0;
foreach( DictionaryEntry de in IEnum ) { ICloneType = de.Value.GetType().GetInterface( "ICloneable" , true );
if( ICloneType != null )<a href=""></a>
{ ICloneable clone = (ICloneable)de.Value;
dic[de.Key] = clone.Clone(); } j++; }
My Clone class
public class DictionaryClass : BaseObject { public Dictionary<int, System.Random> Dic = new Dictionary<int, System.Random>(); }
When clone the DictionaryClass to the other DictionaryClass, In code "foreach( DictionaryEntry de in IEnum )" will throw InvalidCastException
Error message: Specified cast is not valid.
|
|
|
|
 |
|
 |
I find the answer.
else if (IDicType != null) { Dictionary<object, object> newDicCloneObjects = new Dictionary<object, object>(); IDictionary dic = (IDictionary)field.GetValue(aNewObject); IDictionary dicSource = (IDictionary)field.GetValue(aOldObject);
foreach (object key in dicSource.Keys) { if (dicSource[key] != null) { ICloneType = dicSource[key].GetType().GetInterface(C_ICloneable, true); if (ICloneType != null) { ICloneable clone = (ICloneable)dicSource[key]; newDicCloneObjects.Add(key, clone.Clone()); } else
{ newDicCloneObjects.Add(key, CloneObject(dicSource[key])); } } else
{ newDicCloneObjects.Add(key, null); } }
foreach (object key in newDicCloneObjects.Keys) { if (dic.Contains(key) == true) { dic[key] = newDicCloneObjects[key]; } else
{ dic.Add(key, newDicCloneObjects[key]); } } }
|
|
|
|
 |
|
 |
I keep getting Exception saying, "Collection was modified; enumeration operation may not execute". I have references as IList types in 'thisObject' and need to clone them. Any help would be appreciated.
Thanks.
The code that I'm running:
Type IEnumerableType = fi.FieldType.GetInterface("IEnumerable", true); if (IEnumerableType != null) { //Get the IEnumerable interface from the field. IEnumerable IEnum = (IEnumerable)fi.GetValue(thisObj);
//This version support the IList and the IDictionary interfaces to iterate //on collections. Type IListType = fields[i].FieldType.GetInterface("IList", true); Type IDicType = fields[i].FieldType.GetInterface("IDictionary", true);
int j = 0; if (IListType != null) { //Getting the IList interface. IList list = (IList)fields[i].GetValue(newObject);
foreach (object obj in IEnum) { //Checking to see if the current item support the ICloneable interface. ICloneType = obj.GetType().GetInterface("ICloneable", true);
if (ICloneType != 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[j] = clone.Clone(); }
//NOTE: If the item in the list is not support the ICloneable interface then // in the cloned list this item will be the same item as in the original list //(as long as this type is a reference type). j++; } }
|
|
|
|
 |
|
 |
Hello
Did you get an answer fot that? I seem to get the same problem.
Best regards,
JM.
|
|
|
|
 |
|
 |
it looks like this code traverses through my arrays, ~1 million indicies, has anyone else noticed this or found a solution
re: So I just took off this whole part if( IEnumerableType != null ) { up to i++, and it seems to work fine, that was looping through any array
modified on Wednesday, July 16, 2008 4:50 PM
|
|
|
|
 |
|
 |
Hi there! I've got a problem with this code i cannot understand. In the very beginning there is following code
FieldInfo[] fields = newObject.GetType().GetFields();
And the problem is that it is returning empty set. and none of the fields are being copied.
What might be the reason?
|
|
|
|
 |
|
|
 |
|
 |
private/protected described on pg 2 of forum
modified on Tuesday, July 15, 2008 11:59 AM
|
|
|
|
 |
|
 |
I had to quickly clone my big data class, so I tried it but it didn't worked for me at all. So I quickly wrote the following code (VB)
Inside Clone function:
Dim newObject As Object = Activator.CreateInstance(Me.[GetType]())
Dim fields As PropertyInfo() = newObject.[GetType]().GetProperties For Each p As PropertyInfo In fields If p.CanWrite And p.CanRead Then Dim thisProperty As PropertyInfo = Me.GetType().GetProperty(p.Name) p.SetValue(newObject, thisProperty.GetValue(Me, Nothing), Nothing) End If Next
Return newObject
Maybe, it work for someone else too (worked for me atleast).
|
|
|
|
 |
|
 |
Your implementation does only perform a shallow copy of the object, which is already provided in the Object class (method MemberWiseClone).
|
|
|
|
 |
|
 |
First of all thankyou for your implementation of cloning objects, I tryied something similar but was not as complete as yours.
=== BINDING FLAGS === Second, when I was reading and developing my Clonse class one of the first things i've learned is the use of BindingFalgs, which allow you to accurate the search of fields.
With your aproach, not all the fields are retrieved when .GetType().GetFields() is called, becaus you aren't passing any BindingFlags parameter. This affects a lot to the clonation because, for example, private members are not cloned.
Here my contribution:
Replace this code:
FieldInfo[] fields = newObject.GetType().GetFields(bf); int i = 0; foreach (FieldInfo fi in ObjectToClone.GetType().GetFields(bf)) { ... }
For this one:
BindingFlags bf = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static;
FieldInfo[] fields = newObject.GetType().GetFields(bf); int i = 0; foreach (FieldInfo fi in ObjectToClone.GetType().GetFields(bf)) { ... }
You can find more info in this article: Reflector.
=== GENERICS ===
Apply generics to this aproach is very simple, but must change a little bit the philosophy of the class.
implementing ICloneable.Clone forces you to return object, while we want to use Generics. This implies that our Clone function must return the correct type.
So we can do something like:
public T Clone(T ObjectToClone){ ... }
But this implies not being implementing ICloneable.
The result of all of this is that if you want to use generics for clonation you can't implement ICloneable interface.
The solution i've found is to develp an static class T with an static function T Clone(T ObjectToClone), and use it as a tool when we need to clone. The code resutls very smart:
CLONATOR:
public static Clonator < T > { public static T Clone(ref T ObjectToClone) { } }
How yo use it:
MyClass a = new MyClass(..);
MyClass b = Clonator< MyClass >.Clone(ref a);
Of course you are free to test it and tell me your xperience!
-- modified at 5:43 Thursday 15th November, 2007
|
|
|
|
 |
|
 |
How would you modify this to accept generic lists?
|
|
|
|
 |
|
 |
I changed the Sourcecode to support Generic Lists. Also I Kicked out the i++ iterations, as we didn't need them realy.
public object Clone() { object newObject = Activator.CreateInstance(this.GetType());
foreach (FieldInfo fi in this.GetType().GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)) { Type ICloneType = fi.FieldType. GetInterface("ICloneable", true);
if (ICloneType != null) { ICloneable IClone = (ICloneable)fi.GetValue(this);
fi.SetValue(newObject, IClone.Clone()); } else
{ if(fi.FieldType.GetInterface("IEnumerable",true) != null) { fi.SetValue(newObject, Activator.CreateInstance(fi.FieldType)); } else
{ fi.SetValue(newObject, fi.GetValue(this)); } }
Type IEnumerableType = fi.FieldType.GetInterface ("IEnumerable", true); if (IEnumerableType != null) { IEnumerable IEnum = (IEnumerable)fi.GetValue(this);
Type IListType = fi.FieldType.GetInterface ("IList", true); Type IDicType = fi.FieldType.GetInterface ("IDictionary", true);
if (IListType != null) { IList list = (IList)fi.GetValue(newObject);
foreach (object obj in IEnum) { ICloneType = obj.GetType(). GetInterface("ICloneable", true);
if (ICloneType != null) { ICloneable clone = (ICloneable)obj; list.Add(clone.Clone()); }
} } else if (IDicType != null) { IDictionary dic = (IDictionary)fi. GetValue(newObject);
foreach (DictionaryEntry de in IEnum) { ICloneType = de.Value.GetType(). GetInterface("ICloneable", true);
if (ICloneType != null) { ICloneable clone = (ICloneable)de.Value; dic.Add(de.Key, clone.Clone()); } } } } } return newObject; }
It just works fine for me.
|
|
|
|
 |
|
 |
Generic List works fine, and how to support Generic Dictionary? The code "foreach (DictionaryEntry de in IEnum)" will throw an InvalidCastException.
So I changed the code to clone Generic Dictionary as follow:
else if (IDicType != null) { IDictionary dic = (IDictionary)fi.GetValue(newObject); IDictionary dicSource = (IDictionary)fi.GetValue(this); foreach (object key in dicSource.Keys) { ICloneType = dicSource[key].GetType().GetInterface("ICloneable", true); if (ICloneType != null) { ICloneable clone = (ICloneable)dicSource[key]; dic.Add(key, clone.Clone()); } else
dic.Add(key, dicSource[key]); } }
modified on Tuesday, November 25, 2008 2:49 AM
|
|
|
|
 |
|
 |
Thanks a million to the original author as well as the above modification for generics. Saved me a night's work. I have a very similar technique for cloning my entities. However recently I introduced generic collections in some of my entities down the the hierarchy. This code helped me clone them as well.
One difference I have is instead of fields I clone properties.
Thanks a ton once again. -Sumit.
|
|
|
|
 |
|
 |
Hello
If I have a class like the following, how can I use your approach to assign the event handlers to the new cloned object?
public class MyTextBox : TextBox, ICloneable { public object Clone() { MyTextBox clone = new MyTextBox(); clone.Click += this.Click; The event '....Click' can only appear on the left hand side of += or -= } }
Mohammed Hamid A.
|
|
|
|
 |
|
 |
Hello,
I had to reuse this implementation on my own classes with different specifications: - we only wanted to copy primitive types plus some "basic" .NET types (string, enum, DateTime...) - we needed to copy all the inherited members - we only wanted to copy non public fields
I also noticed that GetFields does not necessary return the fields in the same order. I noticed it systematically on the first and second calls but for safety reasons I preferred to lookup the corresponding field every time.
I though I'd post my modified version... Sorry for the comments in french but that is a prerequisite of the project I am working on!
public virtual object Clone() { Objet clone = (Objet) Activator.CreateInstance(this.GetType());
BindingFlags bf = BindingFlags.Instance | BindingFlags.NonPublic;
Type oldType = this.GetType(); Type newType = clone.GetType(); while (oldType != null && newType != null) { FieldInfo[] oldFields = oldType.GetFields(bf); FieldInfo[] newFields = newType.GetFields(bf);
foreach (FieldInfo oldFI in oldFields) { FieldInfo newFI = null; for (int i=0; i { if (newFields[i].Name == oldFI.Name) { newFI = newFields[i]; break; } } if (newFI == null) { continue; }
object value = oldFI.GetValue(this); if (value != null) { if ( oldFI.FieldType.IsPrimitive || oldFI.FieldType.IsEnum || oldFI.FieldType == typeof(String) || oldFI.FieldType == typeof(Decimal) || oldFI.FieldType == typeof(DateTime) || oldFI.FieldType == typeof(TimeSpan)) { newFI.SetValue(clone, value); } } }
oldType = oldType.BaseType; newType = newType.BaseType; }
return clone; }
Voilà!
-- modified at 11:38 Tuesday 25th July, 2006
|
|
|
|
 |
|
 |
Theres a lot of problems in this implementation but the idea has bee kicking around many places..
Before cloning anything in C# read this... It's an excelent article. http://www.agiledeveloper.com/articles/cloning072002.htm
basicly it shows an excelent way to clone.
class myclass() : ICloneable { public readonly int v; protected myclass(myclass another) { v = another.v; }
public object Clone() { return new myclass(this); } }
This is elegant and customisable. If you can't see why then read the article...
Re the serilization "better way"; serialisation may not always be appropriate: -it does not handle all feild types. -not all feilds may be serizable -cpu cost is very high compared to a copy constructor. -public events and delegates tend to get messy. -behavious of serialisation changed from .NET 1.1 to 2.0....
{
|
|
|
|
 |
|
 |
Sleek - but you have to modify the copy constructor if you add a new field to a class - with the solution in this article you don't
|
|
|
|
 |
|
 |
Please consider the following code segment in your article: foreach( object obj in IEnum ) { //Checking to see if the current item //support the ICloneable interface. ICloneType = obj.GetType(). GetInterface( "ICloneable" , true ); if( ICloneType != 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[j] = clone.Clone(); }
//NOTE: If the item in the list is not //support the ICloneable interface then in the //cloned list this item will be the same //item as in the original list //(as long as this type is a reference type).
j++; }
The foreach loop crashes immediately due to this expression: list[j] = clone.Clone(); because you're trying to modify the list contents but an enumerator remains valid as long as the collection remains unchanged. If changes are made to the collection, such as adding, modifying, or deleting elements, the enumerator is irrecoverably invalidated and its behavior is undefined. Any solutions?
Arash Sabet Computer Engineer E-mail: arash.afifi@gmail.com
|
|
|
|
 |
|
 |
Again: If we equip the folliwing if statetment inside the foreach loop you will figure out that list[j] is pointing to the same 'obj' object. That's why an exception is thrown during iteration iEnum object:
if( FieldInfo.ReferenceEquals(list[j],obj) ) { .... }
The above if statemtent returns true, so the body of foreach loop has to be optimized and modified.
Arash Sabet Computer Engineer E-mail: arash.afifi@gmail.com
|
|
|
|
 |
|
 |
Hi,
How could this be implemented. I have a generic List property (List).
regards
Bernd
|
|
|
|
 |
|
 |
Still I believe that this cloning routine is not mature enough to use it in serious applications because:
1. It doesn't clone referenced values. Just sets references! this is not the meaning of deep copying. 2. It doesn't support objects inherited from super classes. The fields of super classes (base classes) can't be iterated in the way that this article describes.
Again this is not a mature article. Just throwing some idea.
Arash Sabet Computer Engineer E-mail: arash.afifi@gmail.com
|
|
|
|
 |