Skip to content

Commit 7af6c03

Browse files
committed
CSHARP-5632: Consolidate driver project Type extension methods in Misc\TypeExtensions.cs
1 parent 4236cf6 commit 7af6c03

File tree

8 files changed

+129
-233
lines changed

8 files changed

+129
-233
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 & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@
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
{
@@ -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))
@@ -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,6 +197,28 @@ 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)
@@ -189,27 +233,15 @@ public static bool IsEnum(this Type type, out Type underlyingType)
189233
}
190234
}
191235

192-
public static bool IsEnum(this Type type, out Type enumType, out Type underlyingType)
236+
public static bool IsEnumOrNullableEnum(this Type type, out Type enumType, out Type underlyingType)
193237
{
194-
if (type.IsEnum)
238+
if (type.IsEnum(out underlyingType))
195239
{
196240
enumType = type;
197-
underlyingType = Enum.GetUnderlyingType(type);
198241
return true;
199242
}
200-
else
201-
{
202-
enumType = null;
203-
underlyingType = null;
204-
return false;
205-
}
206-
}
207243

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);
244+
return IsNullableEnum(type, out enumType, out underlyingType);
213245
}
214246

215247
public static bool IsNullable(this Type type)
@@ -236,18 +268,54 @@ public static bool IsNullableEnum(this Type type)
236268
return type.IsNullable(out var valueType) && valueType.IsEnum;
237269
}
238270

271+
public static bool IsNullableEnum(this Type type, out Type enumType)
272+
{
273+
if (type.IsNullable(out var valueType) && valueType.IsEnum)
274+
{
275+
enumType = valueType;
276+
return true;
277+
}
278+
279+
enumType = null;
280+
return false;
281+
}
282+
239283
public static bool IsNullableEnum(this Type type, out Type enumType, out Type underlyingType)
240284
{
285+
if (type.IsNullable(out var valueType) && valueType.IsEnum(out underlyingType))
286+
{
287+
enumType = valueType;
288+
return true;
289+
}
290+
241291
enumType = null;
242292
underlyingType = null;
243-
return type.IsNullable(out var valueType) && valueType.IsEnum(out enumType, out underlyingType);
293+
return false;
244294
}
245295

246296
public static bool IsNullableOf(this Type type, Type valueType)
247297
{
248298
return type.IsNullable(out var nullableValueType) && nullableValueType == valueType;
249299
}
250300

301+
public static bool IsNumeric(this Type type)
302+
{
303+
return
304+
type == typeof(int) ||
305+
type == typeof(long) ||
306+
type == typeof(double) ||
307+
type == typeof(float) ||
308+
type == typeof(decimal) ||
309+
type == typeof(Decimal128);
310+
}
311+
312+
public static bool IsNumericOrNullableNumeric(this Type type)
313+
{
314+
return
315+
type.IsNumeric() ||
316+
type.IsNullable(out var valueType) && valueType.IsNumeric();
317+
}
318+
251319
public static bool IsSameAsOrNullableOf(this Type type, Type valueType)
252320
{
253321
return type == valueType || type.IsNullableOf(valueType);
@@ -332,5 +400,31 @@ public static bool TryGetIListGenericInterface(this Type type, out Type ilistGen
332400
ilistGenericInterface = null;
333401
return false;
334402
}
403+
404+
public static bool TryGetIQueryableGenericInterface(this Type type, out Type iqueryableGenericInterface)
405+
{
406+
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IQueryable<>))
407+
{
408+
iqueryableGenericInterface = type;
409+
return true;
410+
}
411+
412+
foreach (var interfaceType in type.GetInterfaces())
413+
{
414+
if (interfaceType.IsGenericType && interfaceType.GetGenericTypeDefinition() == typeof(IQueryable<>))
415+
{
416+
iqueryableGenericInterface = interfaceType;
417+
return true;
418+
}
419+
}
420+
421+
iqueryableGenericInterface = null;
422+
return false;
423+
}
424+
425+
private static TValue GetDefaultValueGeneric<TValue>()
426+
{
427+
return default(TValue);
428+
}
335429
}
336430
}

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
{

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

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

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

0 commit comments

Comments
 (0)