mirror of
				https://github.com/art-ist/mustache-sharp.git
				synced 2024-06-16 21:05:32 +00:00 
			
		
		
		
	Handle properties and fields being replaced by derived classes.
I added code that will (correctly) chose the most derived property/field when a conflict exists between the parent and child. According to Microsoft, there is no guarantee of the order that members will be returned, so I had to determine the members distance from the object's type down the inheritance hierarchy and pick the closest.
This commit is contained in:
		
							parent
							
								
									517e38a6db
								
							
						
					
					
						commit
						7bda253bab
					
				@ -1,26 +0,0 @@
 | 
			
		||||
<?xml version="1.0" encoding="UTF-8"?>
 | 
			
		||||
<TestSettings name="Local" id="2bc42439-1bb6-4112-9c20-eca1ffcae064" xmlns="http://microsoft.com/schemas/VisualStudio/TeamTest/2010">
 | 
			
		||||
  <Description>These are default test settings for a local test run.</Description>
 | 
			
		||||
  <Execution>
 | 
			
		||||
    <TestTypeSpecific>
 | 
			
		||||
      <UnitTestRunConfig testTypeId="13cdc9d9-ddb5-4fa4-a97d-d965ccfc6d4b">
 | 
			
		||||
        <AssemblyResolution>
 | 
			
		||||
          <TestDirectory useLoadContext="true" />
 | 
			
		||||
        </AssemblyResolution>
 | 
			
		||||
      </UnitTestRunConfig>
 | 
			
		||||
    </TestTypeSpecific>
 | 
			
		||||
    <AgentRule name="LocalMachineDefaultRole">
 | 
			
		||||
      <DataCollectors>
 | 
			
		||||
        <DataCollector uri="datacollector://microsoft/CodeCoverage/1.0" assemblyQualifiedName="Microsoft.VisualStudio.TestTools.CodeCoverage.CoveragePlugIn, Microsoft.VisualStudio.QualityTools.Plugins.CodeCoverage, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" friendlyName="Code Coverage">
 | 
			
		||||
          <Configuration>
 | 
			
		||||
            <CodeCoverage xmlns="">
 | 
			
		||||
              <Regular>
 | 
			
		||||
                <CodeCoverageItem binaryFile="mustache-sharp\bin\Debug\mustache-sharp.dll" pdbFile="mustache-sharp\bin\Debug\mustache-sharp.pdb" instrumentInPlace="true" />
 | 
			
		||||
              </Regular>
 | 
			
		||||
            </CodeCoverage>
 | 
			
		||||
          </Configuration>
 | 
			
		||||
        </DataCollector>
 | 
			
		||||
      </DataCollectors>
 | 
			
		||||
    </AgentRule>
 | 
			
		||||
  </Execution>
 | 
			
		||||
</TestSettings>
 | 
			
		||||
@ -1,21 +0,0 @@
 | 
			
		||||
<?xml version="1.0" encoding="UTF-8"?>
 | 
			
		||||
<TestSettings name="Trace and Test Impact" id="535ebf31-4d23-42a7-a823-ecb179ff7886" xmlns="http://microsoft.com/schemas/VisualStudio/TeamTest/2010">
 | 
			
		||||
  <Description>These are test settings for Trace and Test Impact.</Description>
 | 
			
		||||
  <Execution>
 | 
			
		||||
    <TestTypeSpecific />
 | 
			
		||||
    <AgentRule name="Execution Agents">
 | 
			
		||||
      <DataCollectors>
 | 
			
		||||
        <DataCollector uri="datacollector://microsoft/SystemInfo/1.0" assemblyQualifiedName="Microsoft.VisualStudio.TestTools.DataCollection.SystemInfo.SystemInfoDataCollector, Microsoft.VisualStudio.TestTools.DataCollection.SystemInfo, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" friendlyName="System Information">
 | 
			
		||||
        </DataCollector>
 | 
			
		||||
        <DataCollector uri="datacollector://microsoft/ActionLog/1.0" assemblyQualifiedName="Microsoft.VisualStudio.TestTools.ManualTest.ActionLog.ActionLogPlugin, Microsoft.VisualStudio.TestTools.ManualTest.ActionLog, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" friendlyName="Actions">
 | 
			
		||||
        </DataCollector>
 | 
			
		||||
        <DataCollector uri="datacollector://microsoft/HttpProxy/1.0" assemblyQualifiedName="Microsoft.VisualStudio.TraceCollector.HttpProxyCollector, Microsoft.VisualStudio.TraceCollector, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" friendlyName="ASP.NET Client Proxy for IntelliTrace and Test Impact">
 | 
			
		||||
        </DataCollector>
 | 
			
		||||
        <DataCollector uri="datacollector://microsoft/TestImpact/1.0" assemblyQualifiedName="Microsoft.VisualStudio.TraceCollector.TestImpactDataCollector, Microsoft.VisualStudio.TraceCollector, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" friendlyName="Test Impact">
 | 
			
		||||
        </DataCollector>
 | 
			
		||||
        <DataCollector uri="datacollector://microsoft/TraceDebugger/1.0" assemblyQualifiedName="Microsoft.VisualStudio.TraceCollector.TraceDebuggerDataCollector, Microsoft.VisualStudio.TraceCollector, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" friendlyName="IntelliTrace">
 | 
			
		||||
        </DataCollector>
 | 
			
		||||
      </DataCollectors>
 | 
			
		||||
    </AgentRule>
 | 
			
		||||
  </Execution>
 | 
			
		||||
</TestSettings>
 | 
			
		||||
@ -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
 | 
			
		||||
 | 
			
		||||
@ -471,6 +471,63 @@ Content";
 | 
			
		||||
            public string Field;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// 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.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        [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; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// 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.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        [TestMethod]
 | 
			
		||||
        public void TestGenerate_NewPropertyInGenericDerivedClass_UsesDerivedProperty()
 | 
			
		||||
        {
 | 
			
		||||
            FormatCompiler compiler = new FormatCompiler();
 | 
			
		||||
            const string format = @"Hello, {{Value}}!!!";
 | 
			
		||||
            Generator generator = compiler.Compile(format);
 | 
			
		||||
            DerivedClass<string> instance = new DerivedClass<string>() { Value = "Derived" };
 | 
			
		||||
            string result = generator.Render(instance);
 | 
			
		||||
            Assert.AreEqual("Hello, Derived!!!", result, "The wrong text was generated.");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public class DerivedClass<T> : BaseClass
 | 
			
		||||
        {
 | 
			
		||||
            public DerivedClass()
 | 
			
		||||
            {
 | 
			
		||||
                base.Value = 1;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            public new T Value { get; set; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        #endregion
 | 
			
		||||
 | 
			
		||||
        #region Comment
 | 
			
		||||
 | 
			
		||||
@ -48,7 +48,7 @@
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <ProjectReference Include="..\mustache-sharp\mustache-sharp.csproj">
 | 
			
		||||
      <Project>{D71B378F-A4BA-4263-A4F0-07A49A0C528D}</Project>
 | 
			
		||||
      <Project>{d71b378f-a4ba-4263-a4f0-07a49a0c528d}</Project>
 | 
			
		||||
      <Name>mustache-sharp</Name>
 | 
			
		||||
    </ProjectReference>
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
 | 
			
		||||
@ -1,6 +0,0 @@
 | 
			
		||||
<?xml version="1.0" encoding="UTF-8"?>
 | 
			
		||||
<TestLists xmlns="http://microsoft.com/schemas/VisualStudio/TeamTest/2010">
 | 
			
		||||
  <TestList name="Lists of Tests" id="8c43106b-9dc1-4907-a29f-aa66a61bf5b6">
 | 
			
		||||
    <RunConfiguration id="2bc42439-1bb6-4112-9c20-eca1ffcae064" name="Local" storage="local.testsettings" type="Microsoft.VisualStudio.TestTools.Common.TestRunConfiguration, Microsoft.VisualStudio.QualityTools.Common, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
 | 
			
		||||
  </TestList>
 | 
			
		||||
</TestLists>
 | 
			
		||||
@ -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")]
 | 
			
		||||
@ -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<string, Func<object, object>>();
 | 
			
		||||
                
 | 
			
		||||
                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<TMember> getMembers<TMember>(Type type, IEnumerable<TMember> 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;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Gets the underlying instance.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user