/// <summary> /// Creates a new CloneType based on a <see cref="System.Type"/>, gathering all the information that is necessary for cloning. /// </summary> /// <param name="type"></param> public CloneType(Type type) { this.type = type.GetTypeInfo(); this.plainOldData = this.type.IsPlainOldData() || typeof(MemberInfo).GetTypeInfo().IsAssignableFrom(this.type); /* Handle MemberInfo like POD */ this.investigateOwnership = !this.plainOldData; this.surrogate = CloneProvider.GetSurrogateFor(this.type); if (this.type.IsArray) { if (this.type.GetArrayRank() > 1) { throw new NotSupportedException( "Cloning multidimensional arrays is not supported in Duality. " + "Consider skipping the referring field via [CloneField] or [DontSerialize] " + "attribute, or use a regular array instead."); } this.elementType = CloneProvider.GetCloneType(this.type.GetElementType()); } CloneBehaviorAttribute defaultBehaviorAttrib = CloneProvider.GetCloneBehaviorAttribute(this.type); if (defaultBehaviorAttrib != null && defaultBehaviorAttrib.Behavior != CloneBehavior.Default) { this.behavior = defaultBehaviorAttrib.Behavior; } else { this.behavior = CloneBehavior.ChildObject; } }
internal static CloneBehaviorAttribute GetCloneBehaviorAttribute(Type type) { // Assembly-level attributes pointing to this Type if (globalCloneBehavior == null) { globalCloneBehavior = ReflectionHelper.GetCustomAssemblyAttributes <CloneBehaviorAttribute>().ToArray(); } for (int i = 0; i < globalCloneBehavior.Length; i++) { CloneBehaviorAttribute globalAttrib = globalCloneBehavior[i]; if (globalAttrib.TargetType.IsAssignableFrom(type)) { return(globalAttrib); } } // Attributes attached directly to this Type CloneBehaviorAttribute directAttrib; if (!cloneBehaviorCache.TryGetValue(type, out directAttrib)) { directAttrib = type.GetCustomAttributes <CloneBehaviorAttribute>().FirstOrDefault(); cloneBehaviorCache[type] = directAttrib; } return(directAttrib); }
public CloneField(FieldInfo field, CloneType typeInfo, CloneFieldFlags flags, CloneBehaviorAttribute behavior, bool isAlwaysReference) { this.field = field; this.typeInfo = typeInfo; this.flags = flags; this.behavior = behavior; this.isAlwaysReference = isAlwaysReference; }
/// <summary> /// Creates a new CloneType based on a <see cref="System.Type"/>, gathering all the information that is necessary for cloning. /// </summary> /// <param name="type"></param> public CloneType(Type type) { this.type = type; this.plainOldData = this.type.IsPlainOldData() || typeof(MemberInfo).IsAssignableFrom(this.type); /* Handle MemberInfo like POD */ this.investigateOwnership = !this.plainOldData; this.surrogate = CloneProvider.GetSurrogateFor(this.type); if (this.type.IsArray) { this.elementType = CloneProvider.GetCloneType(this.type.GetElementType()); } CloneBehaviorAttribute defaultBehaviorAttrib = CloneProvider.GetCloneBehaviorAttribute(this.type); if (defaultBehaviorAttrib != null && defaultBehaviorAttrib.Behavior != CloneBehavior.Default) { this.behavior = defaultBehaviorAttrib.Behavior; } else { this.behavior = CloneBehavior.ChildObject; } }
private List <Expression> CreateSetupFuncContent(Expression setup, Expression source, Expression target) { List <Expression> mainBlock = new List <Expression>(); bool anyContent = false; for (int i = 0; i < this.fieldData.Length; i++) { // Don't need to scan "plain old data" and reference fields if (this.fieldData[i].FieldType.IsPlainOldData) { continue; } if (this.fieldData[i].IsAlwaysReference) { continue; } if (this.fieldData[i].FieldType.Type.IsValueType && !this.fieldData[i].FieldType.InvestigateOwnership) { continue; } anyContent = true; // Call HandleObject on the fields value CloneBehaviorAttribute behaviorAttribute = this.fieldData[i].Behavior; FieldInfo field = this.fieldData[i].Field; Expression handleObjectExpression; if (this.fieldData[i].FieldType.Type.IsValueType) { if (behaviorAttribute == null) { handleObjectExpression = Expression.Call(setup, SetupHandleValue.MakeGenericMethod(field.FieldType), Expression.Field(source, field), Expression.Field(target, field), Expression.Constant(CloneBehavior.Default), Expression.Constant(null, typeof(TypeInfo))); } else { handleObjectExpression = Expression.Call(setup, SetupHandleValue.MakeGenericMethod(field.FieldType), Expression.Field(source, field), Expression.Field(target, field), Expression.Constant(behaviorAttribute.Behavior), Expression.Constant(behaviorAttribute.TargetType)); } } else { if (behaviorAttribute == null) { handleObjectExpression = Expression.Call(setup, SetupHandleObject.MakeGenericMethod(field.FieldType), Expression.Field(source, field), Expression.Field(target, field), Expression.Constant(CloneBehavior.Default), Expression.Constant(null, typeof(TypeInfo))); } else if (behaviorAttribute.TargetType == null || field.FieldType.GetTypeInfo().IsAssignableFrom(behaviorAttribute.TargetType.GetTypeInfo())) { handleObjectExpression = Expression.Call(setup, SetupHandleObject.MakeGenericMethod(field.FieldType), Expression.Field(source, field), Expression.Field(target, field), Expression.Constant(behaviorAttribute.Behavior), Expression.Constant(null, typeof(TypeInfo))); } else { handleObjectExpression = Expression.Call(setup, SetupHandleObject.MakeGenericMethod(field.FieldType), Expression.Field(source, field), Expression.Field(target, field), Expression.Constant(behaviorAttribute.Behavior), Expression.Constant(behaviorAttribute.TargetType)); } } mainBlock.Add(handleObjectExpression); } if (!anyContent) { return(null); } return(mainBlock); }
public void Init() { if (this.surrogate != null) { return; } if (this.plainOldData) { return; } if (this.type.IsArray) { this.investigateOwnership = !(this.elementType.IsPlainOldData || (this.elementType.Type.IsValueType && !this.elementType.InvestigateOwnership)); return; } else { this.investigateOwnership = typeof(ICloneExplicit).GetTypeInfo().IsAssignableFrom(this.type) || this.surrogate != null; } // Retrieve field data List <CloneField> fieldData = new List <CloneField>(); foreach (FieldInfo field in this.type.DeclaredFieldsDeep()) { if (field.IsStatic) { continue; } if (field.IsInitOnly) { continue; } if (field.HasAttributeCached <ManuallyClonedAttribute>()) { continue; } if (field.DeclaringType.GetTypeInfo().HasAttributeCached <ManuallyClonedAttribute>()) { continue; } CloneFieldFlags flags = CloneFieldFlags.None; CloneFieldAttribute fieldAttrib = field.GetAttributesCached <CloneFieldAttribute>().FirstOrDefault(); if (fieldAttrib != null) { flags = fieldAttrib.Flags; } if (field.HasAttributeCached <DontSerializeAttribute>() && !flags.HasFlag(CloneFieldFlags.DontSkip)) { continue; } if (flags.HasFlag(CloneFieldFlags.Skip)) { continue; } CloneBehaviorAttribute behaviorAttrib = field.GetAttributesCached <CloneBehaviorAttribute>().FirstOrDefault(); CloneType fieldType = CloneProvider.GetCloneType(field.FieldType); bool isAlwaysReference = (behaviorAttrib != null) && (behaviorAttrib.TargetType == null || field.FieldType.GetTypeInfo().IsAssignableFrom(behaviorAttrib.TargetType.GetTypeInfo())) && (behaviorAttrib.Behavior == CloneBehavior.Reference); // Can this field own any objects itself? if (!this.investigateOwnership) { bool fieldCanOwnObjects = true; if (fieldType.IsPlainOldData) { fieldCanOwnObjects = false; } if (isAlwaysReference) { fieldCanOwnObjects = false; } if (fieldType.Type.IsValueType && !fieldType.InvestigateOwnership) { fieldCanOwnObjects = false; } if (fieldCanOwnObjects) { this.investigateOwnership = true; } } CloneField fieldEntry = new CloneField(field, fieldType, flags, behaviorAttrib, isAlwaysReference); fieldData.Add(fieldEntry); } this.fieldData = fieldData.ToArray(); // Build precompile functions for setup and (partially) assignment this.CompileAssignmentFunc(); this.CompileSetupFunc(); this.CompileValueAssignmentFunc(); this.CompileValueSetupFunc(); }