Skip to content

Commit 7730685

Browse files
authored
Merge pull request #1867 from for7raid/issue1860
fix constructor with enum parameter crashes
2 parents 6a767b0 + 9b809e3 commit 7730685

File tree

2 files changed

+172
-3
lines changed

2 files changed

+172
-3
lines changed
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using Xunit;
4+
using System.Linq;
5+
6+
namespace LiteDB.Tests.Issues
7+
{
8+
public class Issue1860_Tests
9+
{
10+
[Fact]
11+
public void Constructor_has_enum_bsonctor()
12+
{
13+
using var db = new LiteDatabase(":memory:");
14+
15+
// Get a collection (or create, if doesn't exist)
16+
var col1 = db.GetCollection<C1>("c1");
17+
var col3 = db.GetCollection<C3>("c3");
18+
19+
var c1 = new C1
20+
{
21+
Id = 1,
22+
EnumAB = EnumAB.B
23+
};
24+
25+
col1.Insert(c1);
26+
27+
var c3 = new C3
28+
(
29+
id: 1,
30+
enumAB: EnumAB.B
31+
);
32+
33+
col3.Insert(c3);
34+
35+
var value1 = col1.FindAll().FirstOrDefault();
36+
Assert.NotNull(value1);
37+
Assert.Equal(c1.EnumAB, value1.EnumAB);
38+
39+
var value3 = col3.FindAll().FirstOrDefault();
40+
Assert.NotNull(value3);
41+
Assert.Equal(c3.EnumAB, value3.EnumAB);
42+
}
43+
44+
[Fact]
45+
public void Constructor_has_enum()
46+
{
47+
using var db = new LiteDatabase(":memory:");
48+
49+
// Get a collection (or create, if doesn't exist)
50+
var col1 = db.GetCollection<C1>("c1");
51+
var col2 = db.GetCollection<C2>("c2");
52+
53+
var c1 = new C1
54+
{
55+
Id = 1,
56+
EnumAB = EnumAB.B
57+
};
58+
59+
col1.Insert(c1);
60+
61+
var c2 = new C2
62+
(
63+
id: 1,
64+
enumAB: EnumAB.B
65+
);
66+
67+
col2.Insert(c2);
68+
69+
var value1 = col1.FindAll().FirstOrDefault();
70+
Assert.NotNull(value1);
71+
Assert.Equal(c1.EnumAB, value1.EnumAB);
72+
73+
var value2 = col2.FindAll().FirstOrDefault();
74+
Assert.NotNull(value2);
75+
Assert.Equal(c2.EnumAB, value2.EnumAB);
76+
}
77+
78+
[Fact]
79+
public void Constructor_has_enum_asint()
80+
{
81+
using var db = new LiteDatabase(":memory:", new BsonMapper { EnumAsInteger = true });
82+
83+
// Get a collection (or create, if doesn't exist)
84+
var col1 = db.GetCollection<C1>("c1");
85+
var col2 = db.GetCollection<C2>("c2");
86+
87+
var c1 = new C1
88+
{
89+
Id = 1,
90+
EnumAB = EnumAB.B
91+
};
92+
93+
col1.Insert(c1);
94+
95+
var c2 = new C2
96+
(
97+
id: 1,
98+
enumAB: EnumAB.B
99+
);
100+
101+
col2.Insert(c2);
102+
103+
var value1 = col1.FindAll().FirstOrDefault();
104+
Assert.NotNull(value1);
105+
Assert.Equal(c1.EnumAB, value1.EnumAB);
106+
107+
var value2 = col2.FindAll().FirstOrDefault();
108+
Assert.NotNull(value2);
109+
Assert.Equal(c2.EnumAB, value2.EnumAB);
110+
}
111+
112+
public enum EnumAB
113+
{
114+
115+
A = 1,
116+
B = 2,
117+
}
118+
119+
public class C1
120+
{
121+
public int Id { get; set; }
122+
123+
public EnumAB? EnumAB { get; set; }
124+
}
125+
126+
public class C2
127+
{
128+
public int Id { get; set; }
129+
130+
public EnumAB EnumAB { get; set; }
131+
132+
public C2(int id, EnumAB enumAB)
133+
{
134+
Id = id;
135+
EnumAB = enumAB;
136+
}
137+
}
138+
139+
public class C3
140+
{
141+
public int Id { get; set; }
142+
143+
public EnumAB EnumAB { get; set; }
144+
145+
[BsonCtor]
146+
public C3(int id, EnumAB enumAB)
147+
{
148+
Id = id;
149+
EnumAB = enumAB;
150+
}
151+
}
152+
}
153+
}

LiteDB/Client/Mapper/BsonMapper.cs

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -368,9 +368,9 @@ protected virtual CreateObject GetTypeCtor(EntityMapper mapper)
368368
var ctors = mapper.ForType.GetConstructors();
369369

370370
var ctor =
371-
ctors.FirstOrDefault(x => x.GetCustomAttribute<BsonCtorAttribute>() != null && x.GetParameters().All(p => Reflection.ConvertType.ContainsKey(p.ParameterType) || _basicTypes.Contains(p.ParameterType))) ??
371+
ctors.FirstOrDefault(x => x.GetCustomAttribute<BsonCtorAttribute>() != null && x.GetParameters().All(p => Reflection.ConvertType.ContainsKey(p.ParameterType) || _basicTypes.Contains(p.ParameterType) || p.ParameterType.GetTypeInfo().IsEnum)) ??
372372
ctors.FirstOrDefault(x => x.GetParameters().Length == 0) ??
373-
ctors.FirstOrDefault(x => x.GetParameters().All(p => Reflection.ConvertType.ContainsKey(p.ParameterType) || _customDeserializer.ContainsKey(p.ParameterType) || _basicTypes.Contains(p.ParameterType)));
373+
ctors.FirstOrDefault(x => x.GetParameters().All(p => Reflection.ConvertType.ContainsKey(p.ParameterType) || _customDeserializer.ContainsKey(p.ParameterType) || _basicTypes.Contains(p.ParameterType) || p.ParameterType.GetTypeInfo().IsEnum));
374374

375375
if (ctor == null) return null;
376376

@@ -397,12 +397,28 @@ protected virtual CreateObject GetTypeCtor(EntityMapper mapper)
397397
}
398398
else if (_basicTypes.Contains(p.ParameterType))
399399
{
400-
var typeExpr = Expression.Constant(p.ParameterType);
400+
var typeExpr = Expression.Constant(p.ParameterType);
401401
var rawValue = Expression.Property(expr, typeof(BsonValue).GetProperty("RawValue"));
402402
var convertTypeFunc = Expression.Call(typeof(Convert).GetMethod("ChangeType", new Type[] { typeof(object), typeof(Type) }), rawValue, typeExpr);
403403
var cast = Expression.Convert(convertTypeFunc, p.ParameterType);
404404
pars.Add(cast);
405405
}
406+
else if (p.ParameterType.GetTypeInfo().IsEnum && this.EnumAsInteger)
407+
{
408+
var typeExpr = Expression.Constant(p.ParameterType);
409+
var rawValue = Expression.PropertyOrField(expr, "AsInt32");
410+
var convertTypeFunc = Expression.Call(typeof(Enum).GetMethod("ToObject", new Type[] { typeof(Type), typeof(Int32) }), typeExpr, rawValue);
411+
var cast = Expression.Convert(convertTypeFunc, p.ParameterType);
412+
pars.Add(cast);
413+
}
414+
else if (p.ParameterType.GetTypeInfo().IsEnum)
415+
{
416+
var typeExpr = Expression.Constant(p.ParameterType);
417+
var rawValue = Expression.PropertyOrField(expr, "AsString");
418+
var convertTypeFunc = Expression.Call(typeof(Enum).GetMethod("Parse", new Type[] { typeof(Type), typeof(string) }), typeExpr, rawValue);
419+
var cast = Expression.Convert(convertTypeFunc, p.ParameterType);
420+
pars.Add(cast);
421+
}
406422
else
407423
{
408424
var propInfo = Reflection.ConvertType[p.ParameterType];

0 commit comments

Comments
 (0)