#region Copyright 2010-2014 by Roger Knapp, Licensed under the Apache License, Version 2.0 /* Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #endregion using System; using System.Collections.Generic; using System.Reflection; using System.Runtime.Serialization; namespace CSharpTest.Net.Cloning { /// /// Provides a deep-copy, field-level duplication of any object /// public class MemberwiseClone : ObjectCloner { readonly IDictionary _fieldsCache; /// /// Provides a deep-copy, field-level duplication of any object /// public MemberwiseClone() { _fieldsCache = new Dictionary(); } /// /// Routine to clone an objects fields and their contents /// protected override object CloneDefault(object instance) { Type type = instance.GetType(); object copy = FormatterServices.GetUninitializedObject(type); Graph.Add(instance, copy); MemberInfo[] fields = ClonableFields(type); object[] values = FormatterServices.GetObjectData(instance, fields); for (int i = 0; i < values.Length; i++) values[i] = this.CloneObject(values[i]); FormatterServices.PopulateObjectMembers(copy, fields, values); return copy; } private MemberInfo[] ClonableFields(Type type) { MemberInfo[] result; if (_fieldsCache.TryGetValue(type, out result)) return result; List fields = new List(); Type t = type; while (t != null && t != typeof(Object)) { fields.AddRange( t.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly)); t = t.BaseType; } return _fieldsCache[type] = fields.ToArray(); } } }