Skip to content

Commit cb6895f

Browse files
KenitoIncgathogojr
authored andcommitted
Restructure AggregationBinder
1 parent 8547df7 commit cb6895f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+6020
-571
lines changed

src/Microsoft.AspNetCore.OData/Abstracts/ContainerBuilderExtensions.cs

+1
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ public static IContainerBuilder AddDefaultWebApiServices(this IContainerBuilder
110110
builder.AddService<IFilterBinder, FilterBinder>(ServiceLifetime.Singleton);
111111
builder.AddService<IOrderByBinder, OrderByBinder>(ServiceLifetime.Singleton);
112112
builder.AddService<ISelectExpandBinder, SelectExpandBinder>(ServiceLifetime.Singleton);
113+
builder.AddService<IAggregationBinder, AggregationBinder>(ServiceLifetime.Singleton);
113114

114115
// HttpRequestScope.
115116
builder.AddService<HttpRequestScope>(ServiceLifetime.Scoped);

src/Microsoft.AspNetCore.OData/Common/TypeHelper.cs

+146
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using System;
99
using System.Collections;
1010
using System.Collections.Generic;
11+
using System.Diagnostics;
1112
using System.Diagnostics.CodeAnalysis;
1213
using System.Diagnostics.Contracts;
1314
using System.Linq;
@@ -42,6 +43,84 @@ public static bool IsDynamicTypeWrapper(this Type type)
4243

4344
public static bool IsComputeWrapper(this Type type, out Type entityType) => IsTypeWrapper(typeof(ComputeWrapper<>), type, out entityType);
4445

46+
/// <summary>
47+
/// Determines whether the specified type is a <see cref="FlatteningWrapper{T}"/> or a custom implementation
48+
/// that inherits from <see cref="DynamicTypeWrapper"/> and implements both <see cref="IFlatteningWrapper{T}"/>
49+
/// and <see cref="IGroupByWrapper{TContainer, TWrapper}"/>.
50+
/// </summary>
51+
/// <param name="typeToCheck">The type to check.</param>
52+
/// <returns>
53+
/// <c>true</c> if the specified type is a <see cref="FlatteningWrapper{T}"/> or a custom implementation
54+
/// that meets the criteria; otherwise, <c>false</c>.
55+
/// </returns>
56+
public static bool IsFlatteningWrapper(this Type typeToCheck)
57+
{
58+
if (typeToCheck == null)
59+
{
60+
return false;
61+
}
62+
63+
if (typeToCheck.IsGenericType)
64+
{
65+
Type genericTypeDefinition = typeToCheck.GetGenericTypeDefinition();
66+
67+
// Default implementation
68+
if (genericTypeDefinition == typeof(FlatteningWrapper<>))
69+
{
70+
Debug.Assert(
71+
typeof(DynamicTypeWrapper).IsAssignableFrom(genericTypeDefinition)
72+
&& genericTypeDefinition.ImplementsInterface(typeof(IFlatteningWrapper<>))
73+
&& genericTypeDefinition.ImplementsInterface(typeof(IGroupByWrapper<,>)),
74+
"FlatteningWrapper<T> must inherit from DynamicTypeWrapper and implement IFlatteningWrapper<T> and IGroupByWrapper<TContainer, TWrapper>");
75+
76+
return true;
77+
}
78+
79+
// Custom implementation
80+
// Must inherit from DynamicTypeWrapper
81+
// Must implement IFlatteningWrapper<T> and IGroupByWrapper<TContainer, TWrapper>
82+
return typeof(DynamicTypeWrapper).IsAssignableFrom(genericTypeDefinition) &
83+
genericTypeDefinition.ImplementsInterface(typeof(IFlatteningWrapper<>))
84+
&& genericTypeDefinition.ImplementsInterface(typeof(IGroupByWrapper<,>));
85+
}
86+
87+
return false;
88+
}
89+
90+
/// <summary>
91+
/// Determines whether the specified type is a <see cref="GroupByWrapper"/> or a custom implementation
92+
/// that inherits from <see cref="DynamicTypeWrapper"/> and implements <see cref="IGroupByWrapper{TContainer, TWrapper}"/>.
93+
/// </summary>
94+
/// <param name="typeToCheck">The type to check.</param>
95+
/// <returns>
96+
/// <c>true</c> if the specified type is a <see cref="GroupByWrapper"/> or a custom implementation
97+
/// that meets the criteria; otherwise, <c>false</c>.
98+
/// </returns>
99+
public static bool IsGroupByWrapper(this Type typeToCheck)
100+
{
101+
if (typeToCheck == null || typeToCheck.IsValueType || typeToCheck == typeof(string))
102+
{
103+
return false;
104+
}
105+
106+
// Default implementation
107+
if (typeof(GroupByWrapper).IsAssignableFrom(typeToCheck))
108+
{
109+
Debug.Assert(
110+
typeof(DynamicTypeWrapper).IsAssignableFrom(typeToCheck)
111+
&& typeToCheck.ImplementsInterface(typeof(IGroupByWrapper<,>)),
112+
"GroupByWrapper must inherit from DynamicTypeWrapper and implement IGroupByWrapper<TContainer, TWrapper>");
113+
114+
return true;
115+
}
116+
117+
// Custom implementation
118+
// Must inherit from DynamicTypeWrapper
119+
// Must implement IGroupByWrapper<TContainer, TWrapper>
120+
return typeof(DynamicTypeWrapper).IsAssignableFrom(typeToCheck) &&
121+
typeToCheck.ImplementsInterface(typeof(IGroupByWrapper<,>));
122+
}
123+
45124
private static bool IsTypeWrapper(Type wrappedType, Type type, out Type entityType)
46125
{
47126
if (type == null)
@@ -453,5 +532,72 @@ private static Type GetInnerGenericType(Type interfaceType)
453532

454533
return null;
455534
}
535+
536+
/// <summary>
537+
/// Determines whether the specified type inherits from a given generic base type.
538+
/// </summary>
539+
/// <param name="typeToCheck">The type to examine.</param>
540+
/// <param name="genericBaseType">The open generic type definition to check against (e.g., typeof(Base&lt;&gt;)).</param>
541+
/// <returns><c>true</c> if <paramref name="typeToCheck"/> inherits from <paramref name="genericBaseType"/>; otherwise, <c>false</c>.</returns>
542+
public static bool InheritsFromGenericBase(this Type typeToCheck, Type genericBaseType)
543+
{
544+
if (typeToCheck == null || genericBaseType == null || !genericBaseType.IsGenericTypeDefinition)
545+
return false;
546+
547+
Type baseType = typeToCheck.BaseType;
548+
549+
while (baseType != null && baseType != typeof(object))
550+
{
551+
if (baseType.IsGenericType && baseType.GetGenericTypeDefinition() == genericBaseType)
552+
{
553+
return true;
554+
}
555+
556+
baseType = baseType.BaseType;
557+
}
558+
559+
return false;
560+
}
561+
562+
/// <summary>
563+
/// Determines whether the specified target type implements the given interface type.
564+
/// </summary>
565+
/// <param name="targetType">The type to check for implementation of the interface.</param>
566+
/// <param name="interfaceType">The interface type to check against.</param>
567+
/// <returns>
568+
/// <c>true</c> if the target type implements the specified interface type; otherwise, <c>false</c>.
569+
/// </returns>
570+
/// <remarks>
571+
/// This method supports both generic and non-generic interfaces. For generic interfaces, it checks if the target type
572+
/// implements any interface that matches the generic type definition of the specified interface type.
573+
/// </remarks>
574+
public static bool ImplementsInterface(this Type targetType, Type interfaceType)
575+
{
576+
if (targetType == null || interfaceType == null)
577+
{
578+
return false;
579+
}
580+
581+
if (interfaceType.IsGenericTypeDefinition) // Generic interface (e.g., I<>)
582+
{
583+
Type[] implementedInterfaces = targetType.GetInterfaces();
584+
for (int i = 0; i < implementedInterfaces.Length; i++)
585+
{
586+
Type implementedInterface = implementedInterfaces[i];
587+
588+
if (implementedInterface.IsGenericType &&
589+
implementedInterface.GetGenericTypeDefinition() == interfaceType)
590+
{
591+
return true;
592+
}
593+
}
594+
}
595+
else // Non-generic interface
596+
{
597+
return interfaceType.IsAssignableFrom(targetType);
598+
}
599+
600+
return false;
601+
}
456602
}
457603
}

0 commit comments

Comments
 (0)