In general, in C# it is more convenient to use List than T[]. However, there are times when the profiler shows that List has significant performance penalties compared to natively-implemented bulk operations like Array.Copy and Buffer.BlockCopy. In addition, it is not possible to get pointers to List<> elements.
This makes working with dynamic meshes in Unity somewhat painful. Some of these problems could be alleviated if we could access T[] List._items. Is this possible to do without significant overhead? (either CPU or garbage)
If you know the layout of List, then you can use a dirty trick to cast managed object references. Do not use this unless you're willing to test on every target platform you run on, and re-test with every Unity upgrade.
The most dangerous thing about this is that it breaks invariants about the runtime and compiled type of the object. The compiler will generate code for an object of type TTo, but the object's RTTI field will still show an object of type TFrom.
[StructLayout(LayoutKind.Explicit)]
public struct ConvertHelper<TFrom, TTo>
where TFrom : class
where TTo : class {
[FieldOffset( 0)] public long before;
[FieldOffset( 8)] public TFrom input;
[FieldOffset(16)] public TTo output;
static public TTo Convert(TFrom thing) {
var helper = new ConvertHelper<TFrom, TTo> { input = thing };
unsafe {
long* dangerous = &helper.before;
dangerous[2] = dangerous[1]; // ie, output = input
}
var ret = helper.output;
helper.input = null;
helper.output = null;
return ret;
}
}
class PublicList<T> {
public T[] _items;
}
public static T[] GetBackingArray<T>(this List<T> list) {
return ConvertHelper<List<T>, PublicList<T>>.Convert(list)._items;
}
Using reflection is always possible. This generates a few hundred bytes of garbage for the call to GetValue(). It is also not very fast; on the order of 40 List< T > accesses.
// Helper class for fetching and caching FieldInfo values
class FieldLookup {
string sm_name;
Dictionary<Type, FieldInfo> sm_cache;
public FieldLookup(string name) {
sm_name = name;
sm_cache = new Dictionary<Type, FieldInfo>();
}
public FieldInfo Get(Type t) {
try {
return sm_cache[t];
} catch (KeyNotFoundException) {
var field = sm_cache[t] = t.GetField(
sm_name,
System.Reflection.BindingFlags.NonPublic |
System.Reflection.BindingFlags.GetField |
System.Reflection.BindingFlags.Instance);
return field;
}
}
}
static FieldLookup sm_items = new FieldLookup("_items");
public static T[] GetBackingArray<T>(this List<T> list) {
return (T[])sm_items.Get(typeof(List<T>)).GetValue(list);
}
Related
I'm using the protobuf-net package version 3.0.101.
The following code generates a runtime exception when executing typeModel.Serialize(ms, value). The exception is:
GenericArguments[0], 'UserQuery+Option`1[System.Int32]', on 'ProtoBuf.Serializers.RepeatedSerializer`2[TCollection,T] CreateEnumerable[TCollection,T]()' violates the constraint of type 'TCollection'.
void Main()
{
var typeModel = RuntimeTypeModel.Create();
typeModel.SetSurrogate<Option<int>, OptionSurrogate<int>>();
//typeModel[typeof(Option<int>)].IgnoreListHandling = true; // This doesn't help.
var value = new Option<int>(true, 5);
var ms = new MemoryStream();
typeModel.Serialize(ms, value);
}
struct Option<T> : IEnumerable<T>
{
public Option(bool hasValue, T value)
{
HasValue = hasValue;
Value = value;
}
public readonly bool HasValue;
public readonly T Value;
public IEnumerator<T> GetEnumerator()
{
if (HasValue) {
yield return Value;
}
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
[ProtoContract]
struct OptionSurrogate<T>
{
public OptionSurrogate(Option<T> thing) {
HasValue = thing.HasValue;
Value = thing.Value;
}
[ProtoMember(1)]
public readonly bool HasValue;
[ProtoMember(2)]
public readonly T Value;
public static implicit operator Option<T>(OptionSurrogate<T> surrogate) => new Option<T>(surrogate.HasValue, surrogate.Value);
public static implicit operator OptionSurrogate<T>(Option<T> value) => new OptionSurrogate<T>(value);
}
There are two things that will fix this:
Changing struct Option<T> to class Option<T>
Removing IEnumerable<T> from struct Option<T>
However, neither of these are possible because the struct I want to serialize is in a 3rd party library.
Is this a bug in protobuf-net or is there a workaround?
One possible workaround that might work is wrapping the object in your own class, where you will be able to control which properties get serialized and how.
So I pulled the protobuf repo and stepped through their code for surrogate handling for IEnumerable<T>(the Option<T>) and their implementation makes heavy assumptions that any IEnumerable<T> is an ICollection by default leading to this error. Despite the fact that you explicitly give the runtime the information that Option<T> is not serializable using SetSurrogate, their implementation does not check surrogates until after the item it packed into a more manageable Enumerable type. The problem here is that they're trying to pack:
public IEnumerator<T> GetEnumerator()
{
if (HasValue) {
yield return Value;
}
}
and that's not possible (in-fact they don't even 'see'/'look' for this kind of implementation of IEnumerable.
All that being said, I recommend just explictly casting the objects before and after deserialization, I provided an example that I got working below.
static void Main()
{
var typeModel = RuntimeTypeModel.Create();
var value = new Option<int>(true, 5);
using var writer = new FileInfo("test.txt").OpenWrite();
typeModel.Serialize(writer , (OptionSurrogate<int>)value, typeModel);
writer .Dispose();
using var reader = new FileInfo("test.txt").OpenRead();
Option<int> deserializedValue = (OptionSurrogate<int>)typeModel.Deserialize(reader, null, typeof(OptionSurrogate<int>));
}
Edit
Added simple implementation of ICollection<T> to possibly prevent constraint error
Edit
Added Working work-around this time.
Editors Note
I am not an expert at protobuf and my opinion of how and why this bug is happening is based on some very simple debugging and stepping through their github source. This should not be taken as a fact as I neither wrote protobuf or have worked with the source code of protobuf long enough to properly opine on the cause of this error.
I've got a class which holds a list of ComponentBase. Component sub classes ComponentBase.
public abstract class ComponentBase
{
public Type Type;
public dynamic Value;
public uint EntityID;
}
public class Component<T> : ComponentBase
{
public new Type Type;
public new T Value;
public new uint EntityID;
}
I need a way to retrieve a ref to a Component<T>.Value in the GetComponentOnEntity method and I can't seem to find it. Im not very good at generics so I'll put this question to the pros.
public class ComponentDatabase
{
ComponentBase[] components;
private int componentIndex;
public T AddComponentToEntity<T>(T component, Entity entity) where T : new()
{
var x = component != null ? component : new T();
var comp = new Component<T> { EntityID = entity.Id, Type = typeof(T), Value = x };
components[componentIndex++] = comp;
return x;
}
public ref T GetComponentOnEntity<T>(Entity entity) where T : new()
{
return ref components.Where(x => x.EntityID == entity.Id && x.Type == typeof(T)).First().Value;
}
}
Ive had a long night and I feel like there is a simple solution but I really can't find it. Any help would be greatly appreciated.
Fundamentally, the issue with your code is that you are trying to return a reference to the wrong member of the object. You are returning the member with the dynamic type, when you actually need the member having the type T.
Your original example is equivalent to this simpler one:
class Base
{
public int Id;
public dynamic Value;
public Base(int id, dynamic value)
{
Id = id;
Value = value;
}
public override string ToString() => $"{{Id: {Id}, Value: {Value}}}";
}
class Derived<T> : Base
{
public new int Id;
public new T Value;
public Derived(int id, T value) : base(id, value) { }
}
static void Main(string[] args)
{
Derived<string>[] array = new[]
{
new Derived<string>(0, "Zero"),
new Derived<string>(1, "One"),
new Derived<string>(2, "Two"),
};
ref string valueRef = ref GetElement<string>(array, 1);
valueRef = "Three";
WriteLine(string.Join<Base>(Environment.NewLine, array));
}
private static ref T GetElement<T>(Base[] array, int id)
{
// error CS8151: The return expression must be of type 'T' because this method returns by reference
return ref array.Where(x => x.Id == id).First().Value;
}
The problem is simply that you are trying to return the base class field, which has the type dynamic rather than T.
To fix that, you need to cast the object so that you get the field from the derived type instead:
private static ref T GetElement<T>(Base[] array, int id)
{
return ref ((Derived<T>)array.Where(x => x.Id == id).First()).Value;
}
Or, in your original example:
public ref T GetComponentOnEntity<T>(Entity entity) where T : new()
{
return ref ((Component<T>)components.Where(x => x.EntityID == entity.Id && x.Type == typeof(T)).First()).Value;
}
Now, all that said: I urge you to rethink the design. Perhaps you've omitted some code that initializes the base Value field identically to the derived Value field. But even if so (and that's wasteful enough), there's nothing that prevents those fields from being assigned differently later on. It's not just wasteful, it's also likely to lead to bugs to have an object that has two copies of every value in it, especially when those values are not read-only.
Member hiding (i.e. using the new keyword as you have in your data structures) should be avoided at all costs. It only leads to confusion and will almost certainly result in any number of hard-to-find, hard-to-fix bugs later down the road. The issue you've run into here is just the tip of the iceberg, but is a good example of how confusing things can be when an object has two different members that have the same name.
In addition, ref return values should be used very sparingly, and only when absolutely necessary (e.g. a critical performance issue that can be fixed only using ref return). There's context missing from your question of course, and so maybe you do have a really good reason for using that feature here. But just based on the names in the code that's present, it seems likely to me that you could get the code to work just fine without either of the oddities in the code now (the member hiding and the ref return values).
I need to find out a size of a generic structure (I can not do it like sizeof(T) or using Marshal.SizeOf(...) 0> gives me an error)
So I wrote:
public static class HelperMethods
{
static HelperMethods()
{
SizeOfType = createSizeOfFunc();
}
public static int SizeOf<T>()
{
return SizeOfType(typeof(T));
}
public static readonly Func<Type, int> SizeOfType = null;
private static Func<Type, int> createSizeOfFunc()
{
var dm = new DynamicMethod("SizeOfType", typeof(int), new Type[] { typeof(Type) });
ILGenerator il = dm.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Sizeof); //needs to be il.Emit(OpCodes.Sizeof, typeof(something))
il.Emit(OpCodes.Ret);
var func = (Func<Type, int>)dm.CreateDelegate(typeof(Func<Type, int>));
return func;
}
}
A diffuclty is that il.Emit(OpCodes.Sizeof) needs an argument which I can not pass it during the method (SizeOfType) creation. How can I pass a parameter which is on stack to il.Emit(OpCodes.Sizeof) using IL ? (or a different solution but I want to cache a function (delegate) not a result what is proposed in the 2nd answer)
Taking the above thinking one step further, I arrived at:
public static class TypeSize<T>
{
public readonly static int Size;
static TypeSize()
{
var dm = new DynamicMethod("SizeOfType", typeof(int), new Type[] { });
ILGenerator il = dm.GetILGenerator();
il.Emit(OpCodes.Sizeof, typeof(T));
il.Emit(OpCodes.Ret);
Size = (int)dm.Invoke(null, null);
}
}
...which I believe is the most efficient solution to the problem.
Computing size is something that is fraught with problems because you need to know what is meaningful in the context you are using it. I'd assume there is a good reason for Marshal.SizeOf to throw when the argument is a generic struct, but I don't know what it is.
With that caveat, this code seems to work and gives similar results to Marshal.SizeOf for non-generic structs. It generates a new dynamic method that gets the size via the sizeof IL opcode for the type. It then caches the result (since generating a dynamic method is some what expensive) for future use.
public class A { int x,y,z; }
public struct B { int x,y,z,w,a,b; }
public struct C<T> { Guid g; T b,c,d,e,f; }
public class Program
{
public static void Main(string[] args)
{
Console.WriteLine(IntPtr.Size); // on x86 == 4
Console.WriteLine(SizeHelper.SizeOf(typeof(C<double>))); // prints 56 on x86
Console.WriteLine(SizeHelper.SizeOf(typeof(C<int>))); // prints 36 on x86
}
}
static class SizeHelper
{
private static Dictionary<Type, int> sizes = new Dictionary<Type, int>();
public static int SizeOf(Type type)
{
int size;
if (sizes.TryGetValue(type, out size))
{
return size;
}
size = SizeOfType(type);
sizes.Add(type, size);
return size;
}
private static int SizeOfType(Type type)
{
var dm = new DynamicMethod("SizeOfType", typeof(int), new Type[] { });
ILGenerator il = dm.GetILGenerator();
il.Emit(OpCodes.Sizeof, type);
il.Emit(OpCodes.Ret);
return (int)dm.Invoke(null, null);
}
}
Edit
As far as I can tell there is no way to make non-generic delegate that you can cache. The SizeOf opcode requires a metadata token. It does not take a value from the evaluation stack.
Actually the code below works as well. I'm not sure why Marshal.SizeOf(Type) throws an argument exception when the type is generic structure but Marshal.SizeOf(Object) does not.
public static int SizeOf<T>() where T : struct
{
return Marshal.SizeOf(default(T));
}
It would appear that your aim is to resolve the argument Type from your functions return type Func<Type, int> at compile time. This information is not known at compile time and there is no apparent way to resolve this information using reflection at runtime.
I do not see what benefit returning the the dynamic method serves instead of invoking the dynamic method and returning the result immediately. Given that you have not given any context I would propose the obvious solution, return the value immediately. If your concerns lie with performance then simply cache the results in a dictionary.
public static class GlobalExtensions
{
public static int SizeOf<T>()
{
return SizeOf(typeof (T));
}
public static int SizeOf(this Type type)
{
var dynamicMethod = new DynamicMethod("SizeOf", typeof(int), Type.EmptyTypes);
var generator = dynamicMethod.GetILGenerator();
generator.Emit(OpCodes.Sizeof, type);
generator.Emit(OpCodes.Ret);
var function = (Func<int>) dynamicMethod.CreateDelegate(typeof(Func<int>));
return function();
}
}
Using an extension method leverages some nice syntax. You can now proceed to obtain the size of a generic structure or class using the following code:
var size = TypeExtensions.SizeOf<Example<int>>();
//alternative syntax...
size = typeof (Example<int>).SizeOf();
Now there is possibility for the unmanaged types in unsafe context to do this, if that is sufficient.
private unsafe int MySizeOf<T>() where T : unmanaged
{
return sizeof(T);
}
Ok so in C# I could write:
public class Memorizer<K,TRes>
{
private Dictionary<K,TRes> _mem;
private Func<K,TRes> _function
public Memorizer (Func<K,TRes> function)
{
_function = function;
_mem= new Dictionary<K,TRes>();
}
public TRes Call(K arg)
{
if (mem.ContainsKey(arg)
{
return _mem[arg];
}
else
{
TRes ret=_function(arg);
_mem[arg] = ret;
return ret;
}
}
}
Which could be made use of for obvious gains:
public class FactorialCalculator()
{
private Memorizer<ushort, ulong> _memorizedFactorial;
public FactorialCalculator()
{
_memorizedFactorial = new Memorizer<ushort, ulong> (innerFactorial);
}
private ulong innerFactorial(ushort x)
{
return (x=0) ? 1 : x*Factorial(x-1)
}
public ulong factorial(ushort x)
{
_memorizedFactorial.Call(x);
}
}
I'm sure it could be made more general and elegant.
And I know I'll have overflow exceptions if x>20.
(And I may have typecast errors in there too)
BUt hopefully I made my point: i can create a class that can furful the needs for memoisation of pure mathematical functions (I.e. deterministic, side-effect free functions)
and get wonderful performance gains.
How can I accomplish a similar thing in Java?
In Java 8 you can use the computeIfAbsent to achieve memoization :
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
public class FactorialCalculator {
public static void main(String[] args) {
Function<Integer, Long> factorialFunction = x -> {
System.out.println("Calculating factorial for " + x);
long fact = 1;
for (int i = 1; i <= x; i++) {
fact *= i;
}
return fact;
};
Function<Integer, Long> memoziedFactorialFunction = memoise(factorialFunction);
System.out.println(memoziedFactorialFunction.apply(5));
System.out.println(memoziedFactorialFunction.apply(5));
System.out.println(memoziedFactorialFunction.apply(5));
System.out.println(memoziedFactorialFunction.apply(5));
System.out.println(memoziedFactorialFunction.apply(6));
System.out.println(memoziedFactorialFunction.apply(6));
}
public static <X, Y> Function<X, Y> memoise(Function<X, Y> fn) {
Map<X, Y> pp = new ConcurrentHashMap<X, Y>();
return (a) -> pp.computeIfAbsent(a, fn);
}
}
Result is :
Calculating factorial for 5
120
120
120
120
Calculating factorial for 6
720
720
More details here http://rdafbn.blogspot.ie/2015/06/memoize-functions-in-java-8.html
Lastly, you can use the cyclops library to remove the boilerplate code of creating memoize generic methods( have a look at http://static.javadoc.io/com.aol.cyclops/cyclops-functions/4.0.2/com/aol/cyclops/functions/Memoise.html)
You can't pass functions as data types in java. To fix this, use an interface.
public interface ReturnFunction<K, V> {
public V getValue(K k);
}
Now you can set innerFactorial to a data type.
public ReturnFunction<Short, Long> innerFactorial = new ReturnFunction<Short, Long>(){
public Long getValue(Short x){
return (x=0) ? 1 : x*Factorial(x-1);
}
};
This lets you pass innerFactorial as a data type:
_memoizedFactorial = new Memorizer<Short, Long> (innerFactorial);
And to call the function you write this:
long someLong = _memoizedFactorial.getValue(someShort);
Also, in Java don't capitalize field or method names. It's not standard and makes the code harder to read.
Check out Guava's cache package. This is what it is for.
You can't create a generic map from <short, ulong> in Java because generic type parameters only bind to reference types. You would have to make it <Short, Long> which involves wrapping primitives and may introduce some overhead into your memoization.
Besides that, the translation to Java is pretty straight-forward. Just be aware, you can only memoize types that provide a useful equals and hashCode implementations, and you need to use a size-bounded, thread-safe, weak-key table such as that provided by MapMaker.
I wish to implement a deepcopy of my classes hierarchy in C#
public Class ParentObj : ICloneable
{
protected int myA;
public virtual Object Clone ()
{
ParentObj newObj = new ParentObj();
newObj.myA = theObj.MyA;
return newObj;
}
}
public Class ChildObj : ParentObj
{
protected int myB;
public override Object Clone ( )
{
Parent newObj = this.base.Clone();
newObj.myB = theObj.MyB;
return newObj;
}
}
This will not work as when Cloning the Child only a parent is new-ed. In my code some classes have large hierarchies.
What is the recommended way of doing this? Cloning everything at each level without calling the base class seems wrong? There must be some neat solutions to this problem, what are they?
Can I thank everyone for their answers. It was really interesting to see some of the approaches. I think it would be good if someone gave an example of a reflection answer for completeness. +1 awaiting!
The typical approach is to use "copy constructor" pattern a la C++:
class Base : ICloneable
{
int x;
protected Base(Base other)
{
x = other.x;
}
public virtual object Clone()
{
return new Base(this);
}
}
class Derived : Base
{
int y;
protected Derived(Derived other)
: Base(other)
{
y = other.y;
}
public override object Clone()
{
return new Derived(this);
}
}
The other approach is to use Object.MemberwiseClone in the implementation of Clone - this will ensure that result is always of the correct type, and will allow overrides to extend:
class Base : ICloneable
{
List<int> xs;
public virtual object Clone()
{
Base result = this.MemberwiseClone();
// xs points to same List object here, but we want
// a new List object with copy of data
result.xs = new List<int>(xs);
return result;
}
}
class Derived : Base
{
List<int> ys;
public override object Clone()
{
// Cast is legal, because MemberwiseClone() will use the
// actual type of the object to instantiate the copy.
Derived result = (Derived)base.Clone();
// ys points to same List object here, but we want
// a new List object with copy of data
result.ys = new List<int>(ys);
return result;
}
}
Both approaches require that all classes in the hierarchy follow the pattern. Which one to use is a matter of preference.
If you just have any random class implementing ICloneable with no guarantees on implementation (aside from following the documented semantics of ICloneable), there's no way to extend it.
try the serialization trick:
public object Clone(object toClone)
{
BinaryFormatter bf = new BinaryFormatter();
MemoryStream ms= new MemoryStream();
bf.Serialize(ms, toClone);
ms.Flush();
ms.Position = 0;
return bf.Deserialize(ms);
}
WARNING:
This code should be used with a great deal of caution. Use at your own risk. This example is provided as-is and without a warranty of any kind.
There is one other way to perform a deep clone on an object graph. It is important to be aware of the following when considering using this sample:
Cons:
Any references to external classes will also be cloned unless those references are provided to the Clone(object, ...) method.
No constructors will be executed on cloned objects they are reproduced EXACTLY as they are.
No ISerializable or serialization constructors will be executed.
There is no way to alter the behavior of this method on a specific type.
It WILL clone everything, Stream, AppDomain, Form, whatever, and those will likely break your application in horrific ways.
It could break whereas using the serialization method is much more likely to continue working.
The implementation below uses recursion and can easily cause a stack overflow if your object graph is too deep.
So why would you want to use it?
Pros:
It does a complete deep-copy of all instance data with no coding required in the object.
It preserves all object graph references (even circular) in the reconstituted object.
It's executes more than 20 times fatser than the binary formatter with less memory consumption.
It requires nothing, no attributes, implemented interfaces, public properties, nothing.
Code Usage:
You just call it with an object:
Class1 copy = Clone(myClass1);
Or let's say you have a child object and you are subscribed to it's events... Now you want to clone that child object. By providing a list of objects to not clone, you can preserve some potion of the object graph:
Class1 copy = Clone(myClass1, this);
Implementation:
Now let's get the easy stuff out of the way first... Here is the entry point:
public static T Clone<T>(T input, params object[] stableReferences)
{
Dictionary<object, object> graph = new Dictionary<object, object>(new ReferenceComparer());
foreach (object o in stableReferences)
graph.Add(o, o);
return InternalClone(input, graph);
}
Now that is simple enough, it just builds a dictionary map for the objects during the clone and populates it with any object that should not be cloned. You will note the comparer provided to the dictionary is a ReferenceComparer, let's take a look at what it does:
class ReferenceComparer : IEqualityComparer<object>
{
bool IEqualityComparer<object>.Equals(object x, object y)
{ return Object.ReferenceEquals(x, y); }
int IEqualityComparer<object>.GetHashCode(object obj)
{ return RuntimeHelpers.GetHashCode(obj); }
}
That was easy enough, just a comparer that forces the use of the System.Object's get hash and reference equality... now comes the hard work:
private static T InternalClone<T>(T input, Dictionary<object, object> graph)
{
if (input == null || input is string || input.GetType().IsPrimitive)
return input;
Type inputType = input.GetType();
object exists;
if (graph.TryGetValue(input, out exists))
return (T)exists;
if (input is Array)
{
Array arItems = (Array)((Array)(object)input).Clone();
graph.Add(input, arItems);
for (long ix = 0; ix < arItems.LongLength; ix++)
arItems.SetValue(InternalClone(arItems.GetValue(ix), graph), ix);
return (T)(object)arItems;
}
else if (input is Delegate)
{
Delegate original = (Delegate)(object)input;
Delegate result = null;
foreach (Delegate fn in original.GetInvocationList())
{
Delegate fnNew;
if (graph.TryGetValue(fn, out exists))
fnNew = (Delegate)exists;
else
{
fnNew = Delegate.CreateDelegate(input.GetType(), InternalClone(original.Target, graph), original.Method, true);
graph.Add(fn, fnNew);
}
result = Delegate.Combine(result, fnNew);
}
graph.Add(input, result);
return (T)(object)result;
}
else
{
Object output = FormatterServices.GetUninitializedObject(inputType);
if (!inputType.IsValueType)
graph.Add(input, output);
MemberInfo[] fields = inputType.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
object[] values = FormatterServices.GetObjectData(input, fields);
for (int i = 0; i < values.Length; i++)
values[i] = InternalClone(values[i], graph);
FormatterServices.PopulateObjectMembers(output, fields, values);
return (T)output;
}
}
You will notice right-off the special case for array and delegate copy. Each have their own reasons, first Array does not have 'members' that can be cloned, so you have to handle this and depend on the shallow Clone() member and then clone each element. As for the delegate it may work without the special-case; however, this will be far safer since it's not duplicating things like RuntimeMethodHandle and the like. If you intend to include other things in your hierarchy from the core runtime (like System.Type) I suggest you handle them explicitly in similar fashion.
The last case, and most common, is simply to use roughly the same routines that are used by the BinaryFormatter. These allow us to pop all the instance fields (public or private) out of the original object, clone them, and stick them into an empty object. The nice thing here is that the GetUninitializedObject returns a new instance that has not had the ctor run on it which could cause issues and slow the performance.
Whether the above works or not will highly depend upon your specific object graph and the data therein. If you control the objects in the graph and know that they are not referencing silly things like a Thread then the above code should work very well.
Testing:
Here is what I wrote to originally test this:
class Test
{
public Test(string name, params Test[] children)
{
Print = (Action<StringBuilder>)Delegate.Combine(
new Action<StringBuilder>(delegate(StringBuilder sb) { sb.AppendLine(this.Name); }),
new Action<StringBuilder>(delegate(StringBuilder sb) { sb.AppendLine(this.Name); })
);
Name = name;
Children = children;
}
public string Name;
public Test[] Children;
public Action<StringBuilder> Print;
}
static void Main(string[] args)
{
Dictionary<string, Test> data2, data = new Dictionary<string, Test>(StringComparer.OrdinalIgnoreCase);
Test a, b, c;
data.Add("a", a = new Test("a", new Test("a.a")));
a.Children[0].Children = new Test[] { a };
data.Add("b", b = new Test("b", a));
data.Add("c", c = new Test("c"));
data2 = Clone(data);
Assert.IsFalse(Object.ReferenceEquals(data, data2));
//basic contents test & comparer
Assert.IsTrue(data2.ContainsKey("a"));
Assert.IsTrue(data2.ContainsKey("A"));
Assert.IsTrue(data2.ContainsKey("B"));
//nodes are different between data and data2
Assert.IsFalse(Object.ReferenceEquals(data["a"], data2["a"]));
Assert.IsFalse(Object.ReferenceEquals(data["a"].Children[0], data2["a"].Children[0]));
Assert.IsFalse(Object.ReferenceEquals(data["B"], data2["B"]));
Assert.IsFalse(Object.ReferenceEquals(data["B"].Children[0], data2["B"].Children[0]));
Assert.IsFalse(Object.ReferenceEquals(data["B"].Children[0], data2["A"]));
//graph intra-references still in tact?
Assert.IsTrue(Object.ReferenceEquals(data["B"].Children[0], data["A"]));
Assert.IsTrue(Object.ReferenceEquals(data2["B"].Children[0], data2["A"]));
Assert.IsTrue(Object.ReferenceEquals(data["A"].Children[0].Children[0], data["A"]));
Assert.IsTrue(Object.ReferenceEquals(data2["A"].Children[0].Children[0], data2["A"]));
data2["A"].Name = "anew";
StringBuilder sb = new StringBuilder();
data2["A"].Print(sb);
Assert.AreEqual("anew\r\nanew\r\n", sb.ToString());
}
Final Note:
Honestly it was a fun exercise at the time. It is generally a great thing to have deep cloning on a data model. Today's reality is that most data models are generated which obsoletes the usefulness of the hackery above with a generated deep clone routine. I highly recommend generating your data model & it's ability to perform deep-clones rather than using the code above.
The best way is by serializing your object, then returning the deserialized copy. It will pick up everything about your object, except those marked as non-serializable, and makes inheriting serialization easy.
[Serializable]
public class ParentObj: ICloneable
{
private int myA;
[NonSerialized]
private object somethingInternal;
public virtual object Clone()
{
MemoryStream ms = new MemoryStream();
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(ms, this);
object clone = formatter.Deserialize(ms);
return clone;
}
}
[Serializable]
public class ChildObj: ParentObj
{
private int myB;
// No need to override clone, as it will still serialize the current object, including the new myB field
}
It is not the most performant thing, but neither is the alternative: relection. The benefit of this option is that it seamlessly inherits.
You could use reflection to loop all variables and copy them.(Slow) if its to slow for you software you could use DynamicMethod and generate il.
serialize the object and deserialize it again.
I don't think you are implementing ICloneable correctly here; It requires a Clone() method with no parameters. What I would recommend is something like:
public class ParentObj : ICloneable
{
public virtual Object Clone()
{
var obj = new ParentObj();
CopyObject(this, obj);
}
protected virtual CopyObject(ParentObj source, ParentObj dest)
{
dest.myA = source.myA;
}
}
public class ChildObj : ParentObj
{
public override Object Clone()
{
var obj = new ChildObj();
CopyObject(this, obj);
}
public override CopyObject(ChildObj source, ParentObj dest)
{
base.CopyObject(source, dest)
dest.myB = source.myB;
}
}
Note that CopyObject() is basically Object.MemberwiseClone(), presumeably you would be doing more than just copying values, you would also be cloning any members that are classes.
Try to use the following [use the keyword "new"]
public class Parent
{
private int _X;
public int X{ set{_X=value;} get{return _X;}}
public Parent copy()
{
return new Parent{X=this.X};
}
}
public class Child:Parent
{
private int _Y;
public int Y{ set{_Y=value;} get{return _Y;}}
public new Child copy()
{
return new Child{X=this.X,Y=this.Y};
}
}
You should use the MemberwiseClone method instead:
public class ParentObj : ICloneable
{
protected int myA;
public virtual Object Clone()
{
ParentObj newObj = this.MemberwiseClone() as ParentObj;
newObj.myA = this.MyA; // not required, as value type (int) is automatically already duplicated.
return newObj;
}
}
public class ChildObj : ParentObj
{
protected int myB;
public override Object Clone()
{
ChildObj newObj = base.Clone() as ChildObj;
newObj.myB = this.MyB; // not required, as value type (int) is automatically already duplicated
return newObj;
}
}