Skip to content

Commit 4c5d79a

Browse files
authored
CSHARP-5632: Consolidate driver project Type extension methods in Misc\TypeExtensions.cs (#1815)
1 parent ccbfd79 commit 4c5d79a

File tree

8 files changed

+129
-282
lines changed

8 files changed

+129
-282
lines changed

src/MongoDB.Driver/FieldValueSerializerHelper.cs

Lines changed: 13 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
using MongoDB.Bson;
2121
using MongoDB.Bson.Serialization;
2222
using MongoDB.Bson.Serialization.Serializers;
23-
using MongoDB.Driver.Support;
23+
using MongoDB.Driver.Linq.Linq3Implementation.Misc;
2424

2525
namespace MongoDB.Driver
2626
{
@@ -63,7 +63,7 @@ public static IBsonSerializer GetSerializerForValueType(IBsonSerializer fieldSer
6363
var fieldSerializerInterfaceType = typeof(IBsonSerializer<>).MakeGenericType(fieldType);
6464

6565
// synthesize a NullableSerializer using the field serializer
66-
if (valueType.IsNullable() && valueType.GetNullableUnderlyingType() == fieldType)
66+
if (valueType.IsNullable(out var nonNullableValueType) && nonNullableValueType == fieldType)
6767
{
6868
var nullableSerializerType = typeof(NullableSerializer<>).MakeGenericType(fieldType);
6969
var nullableSerializerConstructor = nullableSerializerType.GetTypeInfo().GetConstructor(new[] { fieldSerializerInterfaceType });
@@ -80,24 +80,21 @@ public static IBsonSerializer GetSerializerForValueType(IBsonSerializer fieldSer
8080
return (IBsonSerializer)enumConvertingSerializerConstructor.Invoke(new object[] { fieldSerializer });
8181
}
8282

83-
if (valueType.IsNullable() && valueType.GetNullableUnderlyingType().IsConvertibleToEnum())
83+
if (valueType.IsNullable(out nonNullableValueType) && nonNullableValueType.IsConvertibleToEnum())
8484
{
85-
var underlyingValueType = valueType.GetNullableUnderlyingType();
86-
var underlyingValueSerializerInterfaceType = typeof(IBsonSerializer<>).MakeGenericType(underlyingValueType);
87-
var enumConvertingSerializerType = typeof(EnumConvertingSerializer<,>).MakeGenericType(underlyingValueType, fieldType);
85+
var nonNullableValueSerializerInterfaceType = typeof(IBsonSerializer<>).MakeGenericType(nonNullableValueType);
86+
var enumConvertingSerializerType = typeof(EnumConvertingSerializer<,>).MakeGenericType(nonNullableValueType, fieldType);
8887
var enumConvertingSerializerConstructor = enumConvertingSerializerType.GetTypeInfo().GetConstructor(new[] { fieldSerializerInterfaceType });
8988
var enumConvertingSerializer = enumConvertingSerializerConstructor.Invoke(new object[] { fieldSerializer });
90-
var nullableSerializerType = typeof(NullableSerializer<>).MakeGenericType(underlyingValueType);
91-
var nullableSerializerConstructor = nullableSerializerType.GetTypeInfo().GetConstructor(new[] { underlyingValueSerializerInterfaceType });
89+
var nullableSerializerType = typeof(NullableSerializer<>).MakeGenericType(nonNullableValueType);
90+
var nullableSerializerConstructor = nullableSerializerType.GetTypeInfo().GetConstructor(new[] { nonNullableValueSerializerInterfaceType });
9291
return (IBsonSerializer)nullableSerializerConstructor.Invoke(new object[] { enumConvertingSerializer });
9392
}
9493
}
9594

9695
// synthesize a NullableEnumConvertingSerializer using the field serializer
97-
if (fieldType.IsNullableEnum() && valueType.IsNullable())
96+
if (fieldType.IsNullableEnum(out var nonNullableFieldType) && valueType.IsNullable(out nonNullableValueType))
9897
{
99-
var nonNullableFieldType = fieldType.GetNullableUnderlyingType();
100-
var nonNullableValueType = valueType.GetNullableUnderlyingType();
10198
var nonNullableFieldSerializer = ((IChildSerializerConfigurable)fieldSerializer).ChildSerializer;
10299
var nonNullableFieldSerializerInterfaceType = typeof(IBsonSerializer<>).MakeGenericType(nonNullableFieldType);
103100
var nullableEnumConvertingSerializerType = typeof(NullableEnumConvertingSerializer<,>).MakeGenericType(nonNullableValueType, nonNullableFieldType);
@@ -106,18 +103,15 @@ public static IBsonSerializer GetSerializerForValueType(IBsonSerializer fieldSer
106103
}
107104

108105
// synthesize an IEnumerableSerializer serializer using the item serializer from the field serializer
109-
Type fieldIEnumerableInterfaceType;
110-
Type valueIEnumerableInterfaceType;
111-
Type itemType;
112106
if (
113-
(fieldIEnumerableInterfaceType = fieldType.FindIEnumerable()) != null &&
114-
(valueIEnumerableInterfaceType = valueType.FindIEnumerable()) != null &&
115-
(itemType = fieldIEnumerableInterfaceType.GetSequenceElementType()) == valueIEnumerableInterfaceType.GetSequenceElementType() &&
107+
fieldType.ImplementsIEnumerable(out var fieldItemType) &&
108+
valueType.ImplementsIEnumerable(out var valueItemType) &&
109+
fieldItemType == valueItemType &&
116110
fieldSerializer is IChildSerializerConfigurable)
117111
{
118112
var itemSerializer = ((IChildSerializerConfigurable)fieldSerializer).ChildSerializer;
119-
var itemSerializerInterfaceType = typeof(IBsonSerializer<>).MakeGenericType(itemType);
120-
var ienumerableSerializerType = typeof(IEnumerableSerializer<>).MakeGenericType(itemType);
113+
var itemSerializerInterfaceType = typeof(IBsonSerializer<>).MakeGenericType(fieldItemType);
114+
var ienumerableSerializerType = typeof(IEnumerableSerializer<>).MakeGenericType(fieldItemType);
121115
var ienumerableSerializerConstructor = ienumerableSerializerType.GetTypeInfo().GetConstructor(new[] { itemSerializerInterfaceType });
122116
return (IBsonSerializer)ienumerableSerializerConstructor.Invoke(new object[] { itemSerializer });
123117
}

src/MongoDB.Driver/Linq/Linq3Implementation/Misc/TypeExtensions.cs

Lines changed: 110 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,15 @@
1616
using System;
1717
using System.Collections.Generic;
1818
using System.Linq;
19+
using System.Reflection;
1920
using System.Runtime.CompilerServices;
21+
using MongoDB.Bson;
2022

2123
namespace MongoDB.Driver.Linq.Linq3Implementation.Misc
2224
{
2325
internal static class TypeExtensions
2426
{
25-
private static readonly Type[] __dictionaryInterfaces =
27+
private static readonly Type[] __dictionaryInterfaceDefinitions =
2628
{
2729
typeof(IDictionary<,>),
2830
typeof(IReadOnlyDictionary<,>)
@@ -52,6 +54,14 @@ internal static class TypeExtensions
5254
typeof(ValueTuple<,,,,,,,>)
5355
};
5456

57+
public static object GetDefaultValue(this Type type)
58+
{
59+
var genericMethod = typeof(TypeExtensions)
60+
.GetMethod(nameof(GetDefaultValueGeneric), BindingFlags.NonPublic | BindingFlags.Static)
61+
.MakeGenericMethod(type);
62+
return genericMethod.Invoke(null, null);
63+
}
64+
5565
public static Type GetIEnumerableGenericInterface(this Type enumerableType)
5666
{
5767
if (enumerableType.TryGetIEnumerableGenericInterface(out var ienumerableGenericInterface))
@@ -92,7 +102,7 @@ public static bool Implements(this Type type, Type @interface)
92102

93103
public static bool ImplementsDictionaryInterface(this Type type, out Type keyType, out Type valueType)
94104
{
95-
if (TryGetGenericInterface(type, __dictionaryInterfaces, out var dictionaryInterface))
105+
if (TryGetGenericInterface(type, __dictionaryInterfaceDefinitions, out var dictionaryInterface))
96106
{
97107
var genericArguments = dictionaryInterface.GetGenericArguments();
98108
keyType = genericArguments[0];
@@ -136,6 +146,18 @@ public static bool ImplementsIList(this Type type, out Type itemType)
136146
return false;
137147
}
138148

149+
public static bool ImplementsIQueryable(this Type type, out Type itemType)
150+
{
151+
if (TryGetIQueryableGenericInterface(type, out var iqueryableType))
152+
{
153+
itemType = iqueryableType.GetGenericArguments()[0];
154+
return true;
155+
}
156+
157+
itemType = null;
158+
return false;
159+
}
160+
139161
public static bool Is(this Type type, Type comparand)
140162
{
141163
if (type == comparand)
@@ -175,41 +197,49 @@ public static bool IsArray(this Type type, out Type itemType)
175197
return false;
176198
}
177199

200+
public static bool IsBooleanOrNullableBoolean(this Type type)
201+
{
202+
return
203+
type == typeof(bool) ||
204+
type.IsNullable(out var valueType) && valueType == typeof(bool);
205+
}
206+
207+
public static bool IsConvertibleToEnum(this Type type)
208+
{
209+
return
210+
type == typeof(sbyte) ||
211+
type == typeof(short) ||
212+
type == typeof(int) ||
213+
type == typeof(long) ||
214+
type == typeof(byte) ||
215+
type == typeof(ushort) ||
216+
type == typeof(uint) ||
217+
type == typeof(ulong) ||
218+
type == typeof(Enum) ||
219+
type == typeof(string);
220+
}
221+
178222
public static bool IsEnum(this Type type, out Type underlyingType)
179223
{
180224
if (type.IsEnum)
181225
{
182226
underlyingType = Enum.GetUnderlyingType(type);
183227
return true;
184228
}
185-
else
186-
{
187-
underlyingType = null;
188-
return false;
189-
}
229+
230+
underlyingType = null;
231+
return false;
190232
}
191233

192-
public static bool IsEnum(this Type type, out Type enumType, out Type underlyingType)
234+
public static bool IsEnumOrNullableEnum(this Type type, out Type enumType, out Type underlyingType)
193235
{
194-
if (type.IsEnum)
236+
if (type.IsEnum(out underlyingType))
195237
{
196238
enumType = type;
197-
underlyingType = Enum.GetUnderlyingType(type);
198239
return true;
199240
}
200-
else
201-
{
202-
enumType = null;
203-
underlyingType = null;
204-
return false;
205-
}
206-
}
207241

208-
public static bool IsEnumOrNullableEnum(this Type type, out Type enumType, out Type underlyingType)
209-
{
210-
return
211-
type.IsEnum(out enumType, out underlyingType) ||
212-
type.IsNullableEnum(out enumType, out underlyingType);
242+
return IsNullableEnum(type, out enumType, out underlyingType);
213243
}
214244

215245
public static bool IsNullable(this Type type)
@@ -224,23 +254,39 @@ public static bool IsNullable(this Type type, out Type valueType)
224254
valueType = type.GetGenericArguments()[0];
225255
return true;
226256
}
227-
else
228-
{
229-
valueType = null;
230-
return false;
231-
}
257+
258+
valueType = null;
259+
return false;
232260
}
233261

234262
public static bool IsNullableEnum(this Type type)
235263
{
236264
return type.IsNullable(out var valueType) && valueType.IsEnum;
237265
}
238266

267+
public static bool IsNullableEnum(this Type type, out Type enumType)
268+
{
269+
if (type.IsNullable(out var valueType) && valueType.IsEnum)
270+
{
271+
enumType = valueType;
272+
return true;
273+
}
274+
275+
enumType = null;
276+
return false;
277+
}
278+
239279
public static bool IsNullableEnum(this Type type, out Type enumType, out Type underlyingType)
240280
{
281+
if (type.IsNullable(out var valueType) && valueType.IsEnum(out underlyingType))
282+
{
283+
enumType = valueType;
284+
return true;
285+
}
286+
241287
enumType = null;
242288
underlyingType = null;
243-
return type.IsNullable(out var valueType) && valueType.IsEnum(out enumType, out underlyingType);
289+
return false;
244290
}
245291

246292
public static bool IsNullableOf(this Type type, Type valueType)
@@ -256,6 +302,24 @@ public static bool IsReadOnlySpanOf(this Type type, Type itemType)
256302
type.GetGenericArguments()[0] == itemType;
257303
}
258304

305+
public static bool IsNumeric(this Type type)
306+
{
307+
return
308+
type == typeof(int) ||
309+
type == typeof(long) ||
310+
type == typeof(double) ||
311+
type == typeof(float) ||
312+
type == typeof(decimal) ||
313+
type == typeof(Decimal128);
314+
}
315+
316+
public static bool IsNumericOrNullableNumeric(this Type type)
317+
{
318+
return
319+
type.IsNumeric() ||
320+
type.IsNullable(out var valueType) && valueType.IsNumeric();
321+
}
322+
259323
public static bool IsSameAsOrNullableOf(this Type type, Type valueType)
260324
{
261325
return type == valueType || type.IsNullableOf(valueType);
@@ -298,55 +362,36 @@ public static bool IsValueTuple(this Type type)
298362
__valueTupleTypeDefinitions.Contains(typeDefinition);
299363
}
300364

301-
public static bool TryGetGenericInterface(this Type type, Type[] interfaceDefinitions, out Type genericInterface)
365+
public static bool TryGetGenericInterface(this Type type, Type genericInterfaceDefintion, out Type genericInterface)
302366
{
303367
genericInterface =
304-
type.IsConstructedGenericType && interfaceDefinitions.Contains(type.GetGenericTypeDefinition()) ?
368+
type.IsConstructedGenericType && type.GetGenericTypeDefinition() == genericInterfaceDefintion ?
305369
type :
306-
type.GetInterfaces().FirstOrDefault(i => i.IsConstructedGenericType && interfaceDefinitions.Contains(i.GetGenericTypeDefinition()));
370+
type.GetInterfaces().FirstOrDefault(i => i.IsConstructedGenericType && i.GetGenericTypeDefinition() == genericInterfaceDefintion);
307371
return genericInterface != null;
308372
}
309373

310-
public static bool TryGetIEnumerableGenericInterface(this Type type, out Type ienumerableGenericInterface)
374+
public static bool TryGetGenericInterface(this Type type, Type[] genericInterfaceDefinitions, out Type genericInterface)
311375
{
312-
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IEnumerable<>))
313-
{
314-
ienumerableGenericInterface = type;
315-
return true;
316-
}
317-
318-
foreach (var interfaceType in type.GetInterfaces())
319-
{
320-
if (interfaceType.IsGenericType && interfaceType.GetGenericTypeDefinition() == typeof(IEnumerable<>))
321-
{
322-
ienumerableGenericInterface = interfaceType;
323-
return true;
324-
}
325-
}
326-
327-
ienumerableGenericInterface = null;
328-
return false;
376+
genericInterface =
377+
type.IsConstructedGenericType && genericInterfaceDefinitions.Contains(type.GetGenericTypeDefinition()) ?
378+
type :
379+
type.GetInterfaces().FirstOrDefault(i => i.IsConstructedGenericType && genericInterfaceDefinitions.Contains(i.GetGenericTypeDefinition()));
380+
return genericInterface != null;
329381
}
330382

383+
public static bool TryGetIEnumerableGenericInterface(this Type type, out Type ienumerableGenericInterface)
384+
=> TryGetGenericInterface(type, typeof(IEnumerable<>), out ienumerableGenericInterface);
385+
331386
public static bool TryGetIListGenericInterface(this Type type, out Type ilistGenericInterface)
332-
{
333-
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IList<>))
334-
{
335-
ilistGenericInterface = type;
336-
return true;
337-
}
387+
=> TryGetGenericInterface(type, typeof(IList<>), out ilistGenericInterface);
338388

339-
foreach (var interfaceType in type.GetInterfaces())
340-
{
341-
if (interfaceType.IsGenericType && interfaceType.GetGenericTypeDefinition() == typeof(IList<>))
342-
{
343-
ilistGenericInterface = interfaceType;
344-
return true;
345-
}
346-
}
389+
public static bool TryGetIQueryableGenericInterface(this Type type, out Type iqueryableGenericInterface)
390+
=> TryGetGenericInterface(type, typeof(IQueryable<>), out iqueryableGenericInterface);
347391

348-
ilistGenericInterface = null;
349-
return false;
392+
private static TValue GetDefaultValueGeneric<TValue>()
393+
{
394+
return default(TValue);
350395
}
351396
}
352397
}

src/MongoDB.Driver/Linq/Linq3Implementation/MongoQueryProvider.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@
2121
using MongoDB.Bson;
2222
using MongoDB.Bson.Serialization;
2323
using MongoDB.Driver.Core.Misc;
24+
using MongoDB.Driver.Linq.Linq3Implementation.Misc;
2425
using MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToExecutableQueryTranslators;
25-
using MongoDB.Driver.Support;
2626

2727
namespace MongoDB.Driver.Linq.Linq3Implementation
2828
{
@@ -105,7 +105,11 @@ internal MongoQueryProvider(
105105
// public methods
106106
public override IQueryable CreateQuery(Expression expression)
107107
{
108-
var outputType = expression.Type.GetSequenceElementType();
108+
if (!expression.Type.ImplementsIQueryable(out var outputType))
109+
{
110+
throw new ExpressionNotSupportedException(expression, because: "expression type does not implement IQueryable");
111+
}
112+
109113
var queryType = typeof(MongoQuery<,>).MakeGenericType(typeof(TDocument), outputType);
110114
return (IQueryable)Activator.CreateInstance(queryType, new object[] { this, expression });
111115
}

src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/BinaryExpressionToAggregationExpressionTranslator.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,9 @@
1818
using MongoDB.Bson.Serialization;
1919
using MongoDB.Bson.Serialization.Serializers;
2020
using MongoDB.Driver.Linq.Linq3Implementation.Ast.Expressions;
21-
using MongoDB.Driver.Linq.Linq3Implementation.ExtensionMethods;
2221
using MongoDB.Driver.Linq.Linq3Implementation.Misc;
2322
using MongoDB.Driver.Linq.Linq3Implementation.Serializers;
2423
using MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToAggregationExpressionTranslators.MethodTranslators;
25-
using MongoDB.Driver.Support;
2624

2725
namespace MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToAggregationExpressionTranslators
2826
{

src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/DefaultIfEmptyMethodToAggregationExpressionTranslator.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
using MongoDB.Driver.Linq.Linq3Implementation.Misc;
2121
using MongoDB.Driver.Linq.Linq3Implementation.Reflection;
2222
using MongoDB.Driver.Linq.Linq3Implementation.Serializers;
23-
using MongoDB.Driver.Support;
2423

2524
namespace MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToAggregationExpressionTranslators.MethodTranslators
2625
{

src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/ElementAtMethodToAggregationExpressionTranslator.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
using MongoDB.Driver.Linq.Linq3Implementation.Ast.Expressions;
1919
using MongoDB.Driver.Linq.Linq3Implementation.Misc;
2020
using MongoDB.Driver.Linq.Linq3Implementation.Reflection;
21-
using MongoDB.Driver.Support;
2221

2322
namespace MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToAggregationExpressionTranslators.MethodTranslators
2423
{

0 commit comments

Comments
 (0)