Skip to content

Commit

Permalink
Improve logic for choosing constructor in type deserializator generator.
Browse files Browse the repository at this point in the history
Now we choose by accessibility level, with importance: public > internal == protected > private and then by number of arguments: giving priority to the argumentless constructor.
  • Loading branch information
vosen committed Mar 4, 2012
1 parent adb4a35 commit fe9b9f5
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 9 deletions.
21 changes: 12 additions & 9 deletions Dapper/SqlMapper.cs
Expand Up @@ -1504,9 +1504,18 @@ static List<FieldInfo> GetSettableFields(Type t)
types[i - startBound] = reader.GetFieldType(i);
}
var constructors = type.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
foreach(ConstructorInfo ctor in constructors)
bool hasDefaultConstructor = false;
foreach (ConstructorInfo ctor in constructors.OrderBy(c => c.IsPublic ? 0 : (c.IsPrivate ? 2 : 1)).ThenBy(c => c.GetParameters().Length))
{
ParameterInfo[] ctorParameters = ctor.GetParameters();
if (ctorParameters.Length == 0)
{
il.Emit(OpCodes.Newobj, ctor);
il.Emit(OpCodes.Stloc_1);
hasDefaultConstructor = true;
break;
}

if (ctorParameters.Length != types.Length)
continue;
int i = 0;
Expand All @@ -1529,15 +1538,9 @@ static List<FieldInfo> GetSettableFields(Type t)
break;
}
}
if(specializedConstructor == null)
if (!hasDefaultConstructor && specializedConstructor == null)
{
var ctor = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
if (ctor == null)
{
throw new InvalidOperationException("A parameterless default constructor is required to allow for dapper materialization");
}
il.Emit(OpCodes.Newobj, ctor);
il.Emit(OpCodes.Stloc_1);
throw new InvalidOperationException("A parameterless default constructor or one matching order, names and types of values returned by the query is required to allow for dapper materialization");
}
}
il.BeginExceptionBlock();
Expand Down
43 changes: 43 additions & 0 deletions Tests/Tests.cs
Expand Up @@ -33,6 +33,49 @@ public class ConcreteOrder : Order
}
}

class MultipleConstructors
{
public MultipleConstructors()
{

}
public MultipleConstructors(int a, string b)
{
A = a + 1;
B = b + "!";
}
public int A { get; set; }
public string B { get; set; }
}

public void TestMultipleConstructors()
{
MultipleConstructors mult = connection.Query<MultipleConstructors>("select 0 A, 'Dapper' b").First();
mult.A.IsEqualTo(0);
mult.B.IsEqualTo("Dapper");
}

class ConstructorsWithAccessModifiers
{
private ConstructorsWithAccessModifiers()
{
}
public ConstructorsWithAccessModifiers(int a, string b)
{
A = a + 1;
B = b + "!";
}
public int A { get; set; }
public string B { get; set; }
}

public void TestConstructorsWithAccessModifiers()
{
ConstructorsWithAccessModifiers value = connection.Query<ConstructorsWithAccessModifiers>("select 0 A, 'Dapper' b").First();
value.A.IsEqualTo(1);
value.B.IsEqualTo("Dapper!");
}

class NoDefaultConstructor
{
public NoDefaultConstructor(int a1, int? b1, float f1, string s1, Guid G1)
Expand Down

0 comments on commit fe9b9f5

Please sign in to comment.