diff --git a/Local.testsettings b/Local.testsettings deleted file mode 100644 index 6522637..0000000 --- a/Local.testsettings +++ /dev/null @@ -1,26 +0,0 @@ - - - These are default test settings for a local test run. - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/TraceAndTestImpact.testsettings b/TraceAndTestImpact.testsettings deleted file mode 100644 index 99dbff3..0000000 --- a/TraceAndTestImpact.testsettings +++ /dev/null @@ -1,21 +0,0 @@ - - - These are test settings for Trace and Test Impact. - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/mustache-sharp.sln b/mustache-sharp.sln index b2c58b0..9a026f2 100644 --- a/mustache-sharp.sln +++ b/mustache-sharp.sln @@ -1,17 +1,10 @@  -Microsoft Visual Studio Solution File, Format Version 11.00 -# Visual Studio 2010 +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "mustache-sharp", "mustache-sharp\mustache-sharp.csproj", "{D71B378F-A4BA-4263-A4F0-07A49A0C528D}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "mustache-sharp.test", "mustache-sharp.test\mustache-sharp.test.csproj", "{7F607362-0680-4751-B1DC-621219294AE3}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{25414E49-67E6-4B8D-8AD8-78C70F8992A7}" - ProjectSection(SolutionItems) = preProject - Local.testsettings = Local.testsettings - mustache-sharp.vsmdi = mustache-sharp.vsmdi - TraceAndTestImpact.testsettings = TraceAndTestImpact.testsettings - EndProjectSection -EndProject Global GlobalSection(TestCaseManagementSettings) = postSolution CategoryFile = mustache-sharp.vsmdi diff --git a/mustache-sharp.test/FormatCompilerTester.cs b/mustache-sharp.test/FormatCompilerTester.cs index dabab3c..c789e85 100644 --- a/mustache-sharp.test/FormatCompilerTester.cs +++ b/mustache-sharp.test/FormatCompilerTester.cs @@ -471,6 +471,63 @@ Content"; public string Field; } + /// + /// If a derived class replaces a property/field in the base class (via new) + /// it should be used, instead of causing an exception or using the base's + /// property/field. + /// + [TestMethod] + public void TestGenerate_NewPropertyInDerivedClass_UsesDerivedProperty() + { + FormatCompiler compiler = new FormatCompiler(); + const string format = @"Hello, {{Value}}!!!"; + Generator generator = compiler.Compile(format); + DerivedClass instance = new DerivedClass() { Value = "Derived" }; + string result = generator.Render(instance); + Assert.AreEqual("Hello, Derived!!!", result, "The wrong text was generated."); + } + + public class BaseClass + { + public int Value { get; set; } + } + + public class DerivedClass : BaseClass + { + public DerivedClass() + { + base.Value = 1; + } + + public new string Value { get; set; } + } + + /// + /// If a derived class replaces a property/field in the base class (via new) + /// it should be used, instead of causing an exception or using the base's + /// property/field. + /// + [TestMethod] + public void TestGenerate_NewPropertyInGenericDerivedClass_UsesDerivedProperty() + { + FormatCompiler compiler = new FormatCompiler(); + const string format = @"Hello, {{Value}}!!!"; + Generator generator = compiler.Compile(format); + DerivedClass instance = new DerivedClass() { Value = "Derived" }; + string result = generator.Render(instance); + Assert.AreEqual("Hello, Derived!!!", result, "The wrong text was generated."); + } + + public class DerivedClass : BaseClass + { + public DerivedClass() + { + base.Value = 1; + } + + public new T Value { get; set; } + } + #endregion #region Comment diff --git a/mustache-sharp.test/mustache-sharp.test.csproj b/mustache-sharp.test/mustache-sharp.test.csproj index 0457468..b0ae5bc 100644 --- a/mustache-sharp.test/mustache-sharp.test.csproj +++ b/mustache-sharp.test/mustache-sharp.test.csproj @@ -48,7 +48,7 @@ - {D71B378F-A4BA-4263-A4F0-07A49A0C528D} + {d71b378f-a4ba-4263-a4f0-07a49a0c528d} mustache-sharp diff --git a/mustache-sharp.vsmdi b/mustache-sharp.vsmdi deleted file mode 100644 index c62973b..0000000 --- a/mustache-sharp.vsmdi +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/mustache-sharp/Properties/AssemblyInfo.cs b/mustache-sharp/Properties/AssemblyInfo.cs index e6f709e..a70745c 100644 --- a/mustache-sharp/Properties/AssemblyInfo.cs +++ b/mustache-sharp/Properties/AssemblyInfo.cs @@ -34,6 +34,6 @@ using System.Runtime.CompilerServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("0.2.3.0")] -[assembly: AssemblyFileVersion("0.2.3.0")] +[assembly: AssemblyVersion("0.2.4.0")] +[assembly: AssemblyFileVersion("0.2.4.0")] [assembly: InternalsVisibleTo("mustache-sharp.test")] \ No newline at end of file diff --git a/mustache-sharp/PropertyDictionary.cs b/mustache-sharp/PropertyDictionary.cs index eb6d66e..0bda944 100644 --- a/mustache-sharp/PropertyDictionary.cs +++ b/mustache-sharp/PropertyDictionary.cs @@ -2,6 +2,7 @@ using System.Collections; using System.Collections.Generic; using System.ComponentModel; +using System.Linq; using System.Reflection; namespace Mustache @@ -40,23 +41,57 @@ namespace Mustache if (!_cache.TryGetValue(type, out typeCache)) { typeCache = new Dictionary>(); + BindingFlags flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy; - foreach (PropertyInfo propertyInfo in type.GetProperties(flags)) + + var properties = getMembers(type, type.GetProperties(flags).Where(p => !p.IsSpecialName)); + foreach (PropertyInfo propertyInfo in properties) { - if (!propertyInfo.IsSpecialName) - { - typeCache.Add(propertyInfo.Name, i => propertyInfo.GetValue(i, null)); - } + typeCache.Add(propertyInfo.Name, i => propertyInfo.GetValue(i, null)); } - foreach (FieldInfo fieldInfo in type.GetFields(flags)) + + var fields = getMembers(type, type.GetFields(flags).Where(f => !f.IsSpecialName)); + foreach (FieldInfo fieldInfo in fields) { typeCache.Add(fieldInfo.Name, i => fieldInfo.GetValue(i)); } + _cache.Add(type, typeCache); } return typeCache; } + private static IEnumerable getMembers(Type type, IEnumerable members) + where TMember : MemberInfo + { + var singles = from member in members + group member by member.Name into nameGroup + where nameGroup.Count() == 1 + from property in nameGroup + select property; + var multiples = from member in members + group member by member.Name into nameGroup + where nameGroup.Count() > 1 + select + ( + from member in nameGroup + orderby getDistance(type, member) + select member + ).First(); + var combined = singles.Concat(multiples); + return combined; + } + + private static int getDistance(Type type, MemberInfo memberInfo) + { + int distance = 0; + for (; type != null && type != memberInfo.DeclaringType; type = type.BaseType) + { + ++distance; + } + return distance; + } + /// /// Gets the underlying instance. ///