PropertyAggregationBug #5
@ -7,9 +7,9 @@ root = true
 | 
			
		||||
#### Core EditorConfig Options ####
 | 
			
		||||
 | 
			
		||||
# Indentation and spacing
 | 
			
		||||
indent_size = 4
 | 
			
		||||
indent_size = 3
 | 
			
		||||
indent_style = tab
 | 
			
		||||
tab_width = 4
 | 
			
		||||
tab_width = 3
 | 
			
		||||
 | 
			
		||||
# New line preferences
 | 
			
		||||
end_of_line = crlf
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										2
									
								
								src/Connected.Caching/SR.Designer.cs
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										2
									
								
								src/Connected.Caching/SR.Designer.cs
									
									
									
										generated
									
									
									
								
							@ -39,7 +39,7 @@ namespace Connected.Caching {
 | 
			
		||||
        internal static global::System.Resources.ResourceManager ResourceManager {
 | 
			
		||||
            get {
 | 
			
		||||
                if (object.ReferenceEquals(resourceMan, null)) {
 | 
			
		||||
                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Server.Caching.SR", typeof(SR).Assembly);
 | 
			
		||||
                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Connected.Caching.SR", typeof(SR).Assembly);
 | 
			
		||||
                    resourceMan = temp;
 | 
			
		||||
                }
 | 
			
		||||
                return resourceMan;
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										2
									
								
								src/Connected.Collections/SR.Designer.cs
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										2
									
								
								src/Connected.Collections/SR.Designer.cs
									
									
									
										generated
									
									
									
								
							@ -39,7 +39,7 @@ namespace Connected.Collections {
 | 
			
		||||
        internal static global::System.Resources.ResourceManager ResourceManager {
 | 
			
		||||
            get {
 | 
			
		||||
                if (object.ReferenceEquals(resourceMan, null)) {
 | 
			
		||||
                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Server.Collections.SR", typeof(SR).Assembly);
 | 
			
		||||
                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Connected.Collections.SR", typeof(SR).Assembly);
 | 
			
		||||
                    resourceMan = temp;
 | 
			
		||||
                }
 | 
			
		||||
                return resourceMan;
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										2
									
								
								src/Connected.Entities/SR.Designer.cs
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										2
									
								
								src/Connected.Entities/SR.Designer.cs
									
									
									
										generated
									
									
									
								
							@ -39,7 +39,7 @@ namespace Connected.Entities {
 | 
			
		||||
        internal static global::System.Resources.ResourceManager ResourceManager {
 | 
			
		||||
            get {
 | 
			
		||||
                if (object.ReferenceEquals(resourceMan, null)) {
 | 
			
		||||
                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Server.Entities.SR", typeof(SR).Assembly);
 | 
			
		||||
                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Connected.Entities.SR", typeof(SR).Assembly);
 | 
			
		||||
                    resourceMan = temp;
 | 
			
		||||
                }
 | 
			
		||||
                return resourceMan;
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										2
									
								
								src/Connected.Hosting/SR.Designer.cs
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										2
									
								
								src/Connected.Hosting/SR.Designer.cs
									
									
									
										generated
									
									
									
								
							@ -39,7 +39,7 @@ namespace Connected.Hosting {
 | 
			
		||||
        internal static global::System.Resources.ResourceManager ResourceManager {
 | 
			
		||||
            get {
 | 
			
		||||
                if (object.ReferenceEquals(resourceMan, null)) {
 | 
			
		||||
                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Server.Hosting.SR", typeof(SR).Assembly);
 | 
			
		||||
                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Connected.Hosting.SR", typeof(SR).Assembly);
 | 
			
		||||
                    resourceMan = temp;
 | 
			
		||||
                }
 | 
			
		||||
                return resourceMan;
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,4 @@
 | 
			
		||||
using Connected.ServiceModel;
 | 
			
		||||
using System.Collections;
 | 
			
		||||
using System.Collections;
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
 | 
			
		||||
namespace Connected.Interop.Merging
 | 
			
		||||
@ -11,7 +10,7 @@ namespace Connected.Interop.Merging
 | 
			
		||||
			if (destination is null || !HasSource(sources))
 | 
			
		||||
				return;
 | 
			
		||||
 | 
			
		||||
			var sourceProperties = AggregateProperties(sources);
 | 
			
		||||
			var sourceProperties = PropertyAggregator.Aggregate(sources);
 | 
			
		||||
 | 
			
		||||
			foreach (var property in Properties.GetImplementedProperties(destination))
 | 
			
		||||
				MergeProperty(destination, sourceProperties, property);
 | 
			
		||||
@ -28,42 +27,6 @@ namespace Connected.Interop.Merging
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private static Dictionary<string, object> AggregateProperties(params object[] sources)
 | 
			
		||||
		{
 | 
			
		||||
			var result = new Dictionary<string, object>();
 | 
			
		||||
 | 
			
		||||
			for (var i = sources.Length - 1; i >= 0; i--)
 | 
			
		||||
			{
 | 
			
		||||
				var source = sources[i];
 | 
			
		||||
 | 
			
		||||
				if (source is null)
 | 
			
		||||
					continue;
 | 
			
		||||
 | 
			
		||||
				var props = Properties.GetImplementedProperties(source);
 | 
			
		||||
 | 
			
		||||
				foreach (var property in props)
 | 
			
		||||
				{
 | 
			
		||||
					if (result.ContainsKey(property.Name))
 | 
			
		||||
						continue;
 | 
			
		||||
 | 
			
		||||
					result.Add(property.Name, source);
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if (source is IPropertyProvider provider)
 | 
			
		||||
				{
 | 
			
		||||
					foreach (var property in provider.Properties)
 | 
			
		||||
					{
 | 
			
		||||
						if (result.ContainsKey(property.Key))
 | 
			
		||||
							continue;
 | 
			
		||||
 | 
			
		||||
						result.Add(property.Key, property.Value);
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			return result;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private void MergeProperty(object destination, Dictionary<string, object> sourceProperties, PropertyInfo property)
 | 
			
		||||
		{
 | 
			
		||||
			if (property.PropertyType.IsTypePrimitive())
 | 
			
		||||
@ -74,7 +37,8 @@ namespace Connected.Interop.Merging
 | 
			
		||||
				if (!sourceProperties.TryGetValue(property.Name, out object? source))
 | 
			
		||||
					return;
 | 
			
		||||
 | 
			
		||||
				property.SetValue(destination, source.GetType().GetProperty(property.Name).GetValue(source));
 | 
			
		||||
				if (source.GetType() is Type propertyType && PropertyResolver.Resolve(propertyType, property.Name) is PropertyInfo propertyInfo)
 | 
			
		||||
					property.SetValue(destination, propertyInfo.GetValue(source));
 | 
			
		||||
			}
 | 
			
		||||
			else if (IsArray(property))
 | 
			
		||||
				MergeEnumerable(destination, sourceProperties, property);
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										68
									
								
								src/Connected.Interop/Merging/PropertyAggregator.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								src/Connected.Interop/Merging/PropertyAggregator.cs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,68 @@
 | 
			
		||||
using Connected.ServiceModel;
 | 
			
		||||
 | 
			
		||||
namespace Connected.Interop.Merging;
 | 
			
		||||
internal static class PropertyAggregator
 | 
			
		||||
{
 | 
			
		||||
	public static Dictionary<string, object> Aggregate(params object[] values)
 | 
			
		||||
	{
 | 
			
		||||
		var result = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
 | 
			
		||||
 | 
			
		||||
		for (var i = values.Length - 1; i >= 0; i--)
 | 
			
		||||
		{
 | 
			
		||||
			if (values[i] is not object value)
 | 
			
		||||
				continue;
 | 
			
		||||
 | 
			
		||||
			foreach (var property in GetImplementedProperties(value))
 | 
			
		||||
			{
 | 
			
		||||
				if (result.ContainsKey(property.Key))
 | 
			
		||||
					continue;
 | 
			
		||||
 | 
			
		||||
				result.Add(property.Key, property.Value);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (value is IPropertyProvider provider)
 | 
			
		||||
			{
 | 
			
		||||
				foreach (var property in provider.Properties)
 | 
			
		||||
				{
 | 
			
		||||
					if (result.ContainsKey(property.Key))
 | 
			
		||||
						continue;
 | 
			
		||||
 | 
			
		||||
					result.Add(property.Key, property.Value);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return result;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private static Dictionary<string, object> GetImplementedProperties(object value)
 | 
			
		||||
	{
 | 
			
		||||
		if (value is null)
 | 
			
		||||
			return new();
 | 
			
		||||
 | 
			
		||||
		if (value is object[] objectArray)
 | 
			
		||||
		{
 | 
			
		||||
			var result = new Dictionary<string, object>();
 | 
			
		||||
 | 
			
		||||
			for (var i = objectArray.Length - 1; i >= 0; i--)
 | 
			
		||||
			{
 | 
			
		||||
				var implementations = Properties.GetImplementedProperties(objectArray[i]);
 | 
			
		||||
 | 
			
		||||
				foreach (var property in implementations)
 | 
			
		||||
					result.Add(property.Name, objectArray[i]);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			return result;
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			var implementations = Properties.GetImplementedProperties(value);
 | 
			
		||||
			var result = new Dictionary<string, object>();
 | 
			
		||||
 | 
			
		||||
			foreach (var property in implementations)
 | 
			
		||||
				result.Add(property.Name, value);
 | 
			
		||||
 | 
			
		||||
			return result;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										19
									
								
								src/Connected.Interop/Merging/PropertyResolver.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								src/Connected.Interop/Merging/PropertyResolver.cs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,19 @@
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
 | 
			
		||||
namespace Connected.Interop.Merging;
 | 
			
		||||
internal static class PropertyResolver
 | 
			
		||||
{
 | 
			
		||||
	public static PropertyInfo? Resolve(Type type, string propertyName)
 | 
			
		||||
	{
 | 
			
		||||
		if (type.GetProperty(propertyName) is PropertyInfo property)
 | 
			
		||||
			return property;
 | 
			
		||||
 | 
			
		||||
		if (type.GetProperty(propertyName.ToCamelCase()) is PropertyInfo camelProperty)
 | 
			
		||||
			return camelProperty;
 | 
			
		||||
 | 
			
		||||
		if (type.GetProperty(propertyName.ToPascalCase()) is PropertyInfo pascalProperty)
 | 
			
		||||
			return pascalProperty;
 | 
			
		||||
 | 
			
		||||
		return null;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										2
									
								
								src/Connected.Interop/SR.Designer.cs
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										2
									
								
								src/Connected.Interop/SR.Designer.cs
									
									
									
										generated
									
									
									
								
							@ -39,7 +39,7 @@ namespace Connected.Interop {
 | 
			
		||||
        internal static global::System.Resources.ResourceManager ResourceManager {
 | 
			
		||||
            get {
 | 
			
		||||
                if (object.ReferenceEquals(resourceMan, null)) {
 | 
			
		||||
                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Server.Interop.SR", typeof(SR).Assembly);
 | 
			
		||||
                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Connected.Interop.SR", typeof(SR).Assembly);
 | 
			
		||||
                    resourceMan = temp;
 | 
			
		||||
                }
 | 
			
		||||
                return resourceMan;
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										2
									
								
								src/Connected.Net/SR.Designer.cs
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										2
									
								
								src/Connected.Net/SR.Designer.cs
									
									
									
										generated
									
									
									
								
							@ -39,7 +39,7 @@ namespace Connected.Net {
 | 
			
		||||
        internal static global::System.Resources.ResourceManager ResourceManager {
 | 
			
		||||
            get {
 | 
			
		||||
                if (object.ReferenceEquals(resourceMan, null)) {
 | 
			
		||||
                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Server.Net.SR", typeof(SR).Assembly);
 | 
			
		||||
                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Connected.Net.SR", typeof(SR).Assembly);
 | 
			
		||||
                    resourceMan = temp;
 | 
			
		||||
                }
 | 
			
		||||
                return resourceMan;
 | 
			
		||||
 | 
			
		||||
@ -1,37 +1,39 @@
 | 
			
		||||
<Project Sdk="Microsoft.NET.Sdk">
 | 
			
		||||
 | 
			
		||||
  <PropertyGroup>
 | 
			
		||||
    <TargetFramework>net7.0</TargetFramework>
 | 
			
		||||
    <ImplicitUsings>enable</ImplicitUsings>
 | 
			
		||||
    <Nullable>enable</Nullable>
 | 
			
		||||
    <RootNamespace>$(MSBuildProjectName.Replace(" ", "_"))</RootNamespace>
 | 
			
		||||
  </PropertyGroup>
 | 
			
		||||
	<PropertyGroup>
 | 
			
		||||
		<TargetFramework>net7.0</TargetFramework>
 | 
			
		||||
		<ImplicitUsings>enable</ImplicitUsings>
 | 
			
		||||
		<Nullable>enable</Nullable>
 | 
			
		||||
		<RootNamespace>$(MSBuildProjectName.Replace(" ", "_"))</RootNamespace>
 | 
			
		||||
	</PropertyGroup>
 | 
			
		||||
 | 
			
		||||
	<ItemGroup>
 | 
			
		||||
		<PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.2.0" />
 | 
			
		||||
		<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="7.0.0-rc.2.22472.3" />
 | 
			
		||||
	</ItemGroup>
 | 
			
		||||
 | 
			
		||||
	<ItemGroup>
 | 
			
		||||
		<ProjectReference Include="..\..\..\Connected\src\Connected\Connected.csproj" />
 | 
			
		||||
    <ProjectReference Include="..\Connected.Configuration\Connected.Configuration.csproj" />
 | 
			
		||||
    <ProjectReference Include="..\Connected.Interop\Connected.Interop.csproj" />
 | 
			
		||||
    <ProjectReference Include="..\Connected.Net\Connected.Net.csproj" />
 | 
			
		||||
    <ProjectReference Include="..\Connected.Services\Connected.Services.csproj" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
		<ProjectReference Include="..\Connected.Configuration\Connected.Configuration.csproj" />
 | 
			
		||||
		<ProjectReference Include="..\Connected.Interop\Connected.Interop.csproj" />
 | 
			
		||||
		<ProjectReference Include="..\Connected.Net\Connected.Net.csproj" />
 | 
			
		||||
		<ProjectReference Include="..\Connected.Services\Connected.Services.csproj" />
 | 
			
		||||
		<ProjectReference Include="..\..\..\connected.framework\src\Connected.Runtime\Connected.Runtime.csproj" />
 | 
			
		||||
	</ItemGroup>
 | 
			
		||||
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <Compile Update="SR.Designer.cs">
 | 
			
		||||
      <DesignTime>True</DesignTime>
 | 
			
		||||
      <AutoGen>True</AutoGen>
 | 
			
		||||
      <DependentUpon>SR.resx</DependentUpon>
 | 
			
		||||
    </Compile>
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
	<ItemGroup>
 | 
			
		||||
		<Compile Update="SR.Designer.cs">
 | 
			
		||||
			<DesignTime>True</DesignTime>
 | 
			
		||||
			<AutoGen>True</AutoGen>
 | 
			
		||||
			<DependentUpon>SR.resx</DependentUpon>
 | 
			
		||||
		</Compile>
 | 
			
		||||
	</ItemGroup>
 | 
			
		||||
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <EmbeddedResource Update="SR.resx">
 | 
			
		||||
      <Generator>ResXFileCodeGenerator</Generator>
 | 
			
		||||
      <LastGenOutput>SR.Designer.cs</LastGenOutput>
 | 
			
		||||
    </EmbeddedResource>
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
	<ItemGroup>
 | 
			
		||||
		<EmbeddedResource Update="SR.resx">
 | 
			
		||||
			<Generator>ResXFileCodeGenerator</Generator>
 | 
			
		||||
			<LastGenOutput>SR.Designer.cs</LastGenOutput>
 | 
			
		||||
		</EmbeddedResource>
 | 
			
		||||
	</ItemGroup>
 | 
			
		||||
 | 
			
		||||
</Project>
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										2
									
								
								src/Connected.Security/SR.Designer.cs
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										2
									
								
								src/Connected.Security/SR.Designer.cs
									
									
									
										generated
									
									
									
								
							@ -39,7 +39,7 @@ namespace Connected.Security {
 | 
			
		||||
        internal static global::System.Resources.ResourceManager ResourceManager {
 | 
			
		||||
            get {
 | 
			
		||||
                if (object.ReferenceEquals(resourceMan, null)) {
 | 
			
		||||
                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Server.Security.SR", typeof(SR).Assembly);
 | 
			
		||||
                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Connected.Security.SR", typeof(SR).Assembly);
 | 
			
		||||
                    resourceMan = temp;
 | 
			
		||||
                }
 | 
			
		||||
                return resourceMan;
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										2
									
								
								src/Connected.Services/SR.Designer.cs
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										2
									
								
								src/Connected.Services/SR.Designer.cs
									
									
									
										generated
									
									
									
								
							@ -39,7 +39,7 @@ namespace Connected.Services {
 | 
			
		||||
        internal static global::System.Resources.ResourceManager ResourceManager {
 | 
			
		||||
            get {
 | 
			
		||||
                if (object.ReferenceEquals(resourceMan, null)) {
 | 
			
		||||
                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Server.Services.SR", typeof(SR).Assembly);
 | 
			
		||||
                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Connected.Services.SR", typeof(SR).Assembly);
 | 
			
		||||
                    resourceMan = temp;
 | 
			
		||||
                }
 | 
			
		||||
                return resourceMan;
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										2
									
								
								src/Connected.Threading/SR.Designer.cs
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										2
									
								
								src/Connected.Threading/SR.Designer.cs
									
									
									
										generated
									
									
									
								
							@ -39,7 +39,7 @@ namespace Connected.Threading {
 | 
			
		||||
        internal static global::System.Resources.ResourceManager ResourceManager {
 | 
			
		||||
            get {
 | 
			
		||||
                if (object.ReferenceEquals(resourceMan, null)) {
 | 
			
		||||
                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Server.Threading.SR", typeof(SR).Assembly);
 | 
			
		||||
                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Connected.Threading.SR", typeof(SR).Assembly);
 | 
			
		||||
                    resourceMan = temp;
 | 
			
		||||
                }
 | 
			
		||||
                return resourceMan;
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user