private static MethodDescription[] GetSerializationCallbacks(Type type, IDictionary <string, TypeDescription> typesByAssemblyQualifiedName) { var attributes = new HashSet <SpecialMethod>(); var methods = type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static); var descriptions = new List <MethodDescription>(); foreach (var method in methods) { var attribute = method.GetCustomAttribute <SerializationMethodAttribute>(); if (attribute != null) { var methodType = attribute.Method; if (attributes.Contains(methodType)) { throw new ArgumentException( string.Format( "The type '{0}.{1}' contains too many methods with the [{2}] attribute: There may not be more than one", type.Namespace, type.Name, methodType)); } attributes.Add(methodType); var description = MethodDescription.Create(method, typesByAssemblyQualifiedName); descriptions.Add(description); } } return(descriptions.ToArray()); }
/// <summary> /// Creates a new description for the given property. /// </summary> /// <param name="declaringType"></param> /// <param name="property"></param> /// <param name="typesByAssemblyQualifiedName"></param> /// <returns></returns> public static PropertyDescription Create(TypeDescription declaringType, PropertyInfo property, IDictionary <string, TypeDescription> typesByAssemblyQualifiedName) { return(new PropertyDescription(declaringType, property) { Name = property.Name, PropertyType = SharpRemote.TypeDescription.GetOrCreate(property.PropertyType, typesByAssemblyQualifiedName), GetMethod = property.GetMethod != null?MethodDescription.Create(property.GetMethod, typesByAssemblyQualifiedName) : null, SetMethod = property.SetMethod != null?MethodDescription.Create(property.SetMethod, typesByAssemblyQualifiedName) : null }); }
internal IEnumerable <ITypeModelDifference> FindDifferences(MethodDescription actualMethod) { var differences = new List <ITypeModelDifference>(); differences.AddRange(ReturnParameter.FindDifferences(actualMethod.ReturnParameter)); if (Parameters.Length != actualMethod.Parameters.Length) { differences.Add(new ParameterCountMismatch(this, actualMethod)); } else { for (int i = 0; i < Parameters.Length; ++i) { var expectedParameter = Parameters[i]; var actualParameter = actualMethod.Parameters[i]; differences.AddRange(expectedParameter.FindDifferences(actualParameter)); } } return(differences); }
/// <summary> /// </summary> /// <param name="methodInfo"></param> /// <param name="typesByAssemblyQualifiedName"></param> /// <returns></returns> public static MethodDescription Create(MethodInfo methodInfo, IDictionary <string, TypeDescription> typesByAssemblyQualifiedName) { var description = new MethodDescription(methodInfo) { ReturnParameter = ParameterDescription.Create(methodInfo.ReturnParameter, typesByAssemblyQualifiedName), }; var parameters = methodInfo.GetParameters(); if (parameters.Length > 0) { description.Parameters = parameters.Select(x => ParameterDescription.Create(x, typesByAssemblyQualifiedName)).ToArray(); } else { description.Parameters = EmptyParameters; } return(description); }
/// <summary> /// Creates a new description for the given type. /// </summary> /// <param name="type"></param> /// <param name="typesByAssemblyQualifiedName"></param> /// <param name="assumeByReference"></param> /// <returns></returns> public static TypeDescription Create(Type type, IDictionary <string, TypeDescription> typesByAssemblyQualifiedName, bool assumeByReference = false) { if (type == null) { throw new ArgumentNullException(nameof(type)); } var assemblyQualifiedName = type.AssemblyQualifiedName; if (assemblyQualifiedName == null) { throw new ArgumentException("Type.AssemblyQualifiedName should not be null"); } bool builtIn, isEnumerable; MethodInfo singletonAccessor; Type byReferenceInterface; var serializerType = GetSerializationType(type, assumeByReference, out builtIn, out isEnumerable, out singletonAccessor, out byReferenceInterface); var description = new TypeDescription(type, byReferenceInterface) { AssemblyQualifiedName = assemblyQualifiedName, SerializationType = serializerType }; typesByAssemblyQualifiedName.Add(assemblyQualifiedName, description); var serializationCallbacks = GetSerializationCallbacks(type, typesByAssemblyQualifiedName); switch (description.SerializationType) { case SerializationType.ByValue: description.Fields = type.GetFields(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly) .Where(x => x.GetCustomAttribute <DataMemberAttribute>() != null) .Select(x => FieldDescription.Create(x, typesByAssemblyQualifiedName)).ToArray(); description.Properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly) .Where(x => x.GetCustomAttribute <DataMemberAttribute>() != null) .Select(x => PropertyDescription.Create(description, x, typesByAssemblyQualifiedName)).ToArray(); description.Methods = serializationCallbacks; break; case SerializationType.ByReference: if (serializationCallbacks.Any()) { throw new ArgumentException( string.Format( "The type '{0}.{1}' is marked with the [ByReference] attribute and thus may not contain serialization callback methods", type.Namespace, type.Name)); } description.Fields = new FieldDescription[0]; description.Properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance) .Select(x => PropertyDescription.Create(description, x, typesByAssemblyQualifiedName)).ToArray(); description.Methods = type.GetMethods(BindingFlags.Public | BindingFlags.Instance) .Where(x => !x.IsSpecialName) .Select(x => MethodDescription.Create(x, typesByAssemblyQualifiedName)).ToArray(); break; case SerializationType.Singleton: if (serializationCallbacks.Any()) { throw new ArgumentException( string.Format( "The type '{0}.{1}' is a singleton and thus may not contain any serialization callbacks", type.Namespace, type.Name)); } description.Fields = new FieldDescription[0]; description.Properties = new PropertyDescription[0]; description.Methods = new[] { MethodDescription.Create(singletonAccessor, typesByAssemblyQualifiedName) }; break; case SerializationType.Unknown: description.Fields = new FieldDescription[0]; description.Properties = new PropertyDescription[0]; description.Methods = new MethodDescription[0]; break; case SerializationType.NotSerializable: // TODO: Throw proper exception with proper error message throw new NotImplementedException(); default: throw new NotImplementedException(); } if (IsInterestingBaseType(type.BaseType)) { description.BaseType = GetOrCreate(type.BaseType, typesByAssemblyQualifiedName); } description.IsBuiltIn = builtIn; description.IsValueType = type.IsValueType; description.IsClass = type.IsClass; description.IsInterface = type.IsInterface; description.IsEnum = type.IsEnum; description.IsEnumerable = isEnumerable; description.IsSealed = type.IsSealed; description.IsGenericType = type.IsGenericType; if (type.IsGenericType) { var genericArguments = type.GetGenericArguments(); var types = new TypeDescription[genericArguments.Length]; for (int i = 0; i < genericArguments.Length; ++i) { types[i] = GetOrCreate(genericArguments[i], typesByAssemblyQualifiedName); } description.GenericArguments = types; } else if (type.IsArray) { description.GenericArguments = new[] { GetOrCreate(type.GetElementType(), typesByAssemblyQualifiedName) }; } else { description.GenericArguments = new TypeDescription[0]; } if (type.IsEnum) { var storageType = Enum.GetUnderlyingType(type); description.StorageType = GetOrCreate(storageType, typesByAssemblyQualifiedName); var values = Enum.GetValues(type).OfType <object>().ToArray(); var names = Enum.GetNames(type); var descriptions = new EnumValueDescription[values.Length]; for (int i = 0; i < names.Length; ++i) { descriptions[i] = EnumValueDescription.Create(storageType, values[i], names[i]); } description.EnumValues = descriptions; } return(description); }