private string GetTypeName(Type t) { try { return(MEF.GetCSharpNameForType(t)); } catch (NotSupportedException) { return(t.Name); } }
public void FindPropertyMisuse(List <string> csFilesFound) { //Find all the types that come from the database var types = typeof(Catalogue).Assembly.GetTypes().Where(t => typeof(DatabaseEntity).IsAssignableFrom(t)); types = types.Union(typeof(Project).Assembly.GetTypes().Where(t => typeof(DatabaseEntity).IsAssignableFrom(t))) .ToArray(); foreach (Type type in types) { //if it's a spont object ignore it if (typeof(SpontaneousObject).IsAssignableFrom(type) || type == typeof(SpontaneouslyInventedColumn) || type == typeof(SpontaneouslyInventedFilter)) { continue; } //Find the C sharp code for the class var relationshipProperties = type.GetProperties().Where(p => p.CanRead && !p.CanWrite); string expectedFileName = type.Name + ".cs"; var files = csFilesFound.Where(f => f.EndsWith("\\" + expectedFileName, StringComparison.CurrentCultureIgnoreCase)).ToArray(); if (files.Length == 0) { _fails.Add("FAIL: Could not find a csFile called '" + expectedFileName + "'"); continue; } if (files.Length > 1) { _fails.Add("FAIL: found multiple csFiles called '" + expectedFileName + "'"); continue; } //Find the #region Relationships bit should contain all the properties which get; database objects or enumerates database objects (These shouldn't have a set;) var classSourceCode = File.ReadAllText(files[0]); Regex r = new Regex("#region Relationships(.*)#endregion", RegexOptions.Singleline); string relationshipsRegion = null; var matches = r.Matches(classSourceCode); if (matches.Count == 1) { relationshipsRegion = matches[0].Groups[1].Value; } if (matches.Count > 1) { _fails.Add("FAIL: Class " + type.FullName + " has multiple '#region Relationships' blocks"); } foreach (PropertyInfo relationshipProperty in relationshipProperties) { if (relationshipProperty.Name.Equals("ID")) { continue; } if (relationshipProperty.CustomAttributes.All(c => c.AttributeType != typeof(NoMappingToDatabase))) { _fails.Add("FAIL: Class " + type.FullName + " has readonly property " + relationshipProperty + " which is not decorated with NoMapping"); continue; } if (!IsRelationshipProperty(relationshipProperty.PropertyType)) { Console.WriteLine("SKIPPED: Property " + relationshipProperty + " is ReadOnly and [NoMapping] but doesn't look like it serves up related objects"); continue; } RelationshipPropertyInfos.Add(relationshipProperty, relationshipProperty.GetGetMethod()); if (relationshipsRegion == null) { _fails.Add("FAIL: Class " + type.FullName + " has no '#region Relationships' blocks but has a relationship style Property called " + relationshipProperty.Name); } else { string expectedString = MEF.GetCSharpNameForType(relationshipProperty.PropertyType) + " " + relationshipProperty.Name; if (!relationshipsRegion.Contains(expectedString)) { _fails.Add("FAIL: Class " + type.FullName + " has a property we expected to be '" + expectedString + "' but it did not appear in the '#region Relationships'"); } } } var databaseProperties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(p => p.CanRead && p.CanWrite); string suggestedFieldDeclarations = ""; string suggestedMethodWrappers = ""; foreach (PropertyInfo p in databaseProperties) { //its a NoMapping if (p.CustomAttributes.Any(c => c.AttributeType == typeof(NoMappingToDatabase))) { continue; } //special case, let this one pass, nobody should be changing it as a user anyway if (p.Name.Equals("ID")) { continue; } var setMethod = p.GetSetMethod(false); if (setMethod == null) { Console.WriteLine("WARNING: Property " + p.Name + " on Type " + type.Name + " has no set or it is not public;"); continue; } if (MightBeCouldBeMaybeAutoGeneratedInstanceProperty(p)) { char firstLetter = p.Name.ToLower()[0]; string fieldName = "_" + firstLetter + p.Name.Substring(1); string typeName = p.PropertyType.Name; if (typeName == "String") { typeName = "string"; } if (typeName == "Int32") { typeName = "int"; } if (typeName == "Boolean") { typeName = "bool"; } if (p.PropertyType == typeof(int?)) { typeName = "int?"; } if (p.PropertyType == typeof(DateTime?)) { typeName = "DateTime?"; } suggestedFieldDeclarations += "private " + typeName + " " + fieldName + ";" + Environment.NewLine; suggestedMethodWrappers += "public " + typeName + " " + p.Name + Environment.NewLine; suggestedMethodWrappers += "{" + Environment.NewLine; suggestedMethodWrappers += "\tget { return " + fieldName + ";}" + Environment.NewLine; suggestedMethodWrappers += "\tset { SetField(ref " + fieldName + ",value);}" + Environment.NewLine; suggestedMethodWrappers += "}" + Environment.NewLine; } if (!setMethod.IsAbstract) { /*var instructions = setMethod.GetInstructions(); * * bool foundINotify = false; * * foreach (Instruction instruction in instructions) * { * MethodInfo methodInfo = instruction.Operand as MethodInfo; * * if (methodInfo != null) * if (methodInfo.Name.Equals("SetField") || methodInfo.Name.Equals("OnPropertyChanged")) * foundINotify = true; * } * * if(!foundINotify) * _fails.Add("FAIL:Set Method for property " + p.Name + " on Type " + type.Name + " does not include an Instruction calling method 'SetField' or 'OnPropertyChanged'"); * */ } } if (!string.IsNullOrWhiteSpace(suggestedMethodWrappers)) { Console.WriteLine("CODE SUGGESTION FOR " + type.Name); Console.WriteLine("#region Database Properties"); Console.WriteLine(suggestedFieldDeclarations); Console.WriteLine(suggestedMethodWrappers); Console.WriteLine("#endregion"); } } AnalyseRelationshipPropertyUsages(); foreach (string fail in _fails) { Console.WriteLine(fail); } Assert.AreEqual(0, _fails.Count); }