提交 9846b9af 编写于 作者: K kevin-montrose

whack at an explicit constructor switch

上级 8e33a56d
......@@ -389,6 +389,15 @@ public interface ITypeMap
/// <returns>Matching constructor or default one</returns>
ConstructorInfo FindConstructor(string[] names, Type[] types);
/// <summary>
/// Returns a constructor which should *always* be used.
///
/// Parameters will be default values, nulls for reference types and zero'd for value types.
///
/// Use this class to force object creation away from parameterless constructors you dn't control.
/// </summary>
ConstructorInfo FindExplicitConstructor();
/// <summary>
/// Gets mapping for constructor parameter
/// </summary>
......@@ -3557,26 +3566,67 @@ public static void SetTypeMap(Type type, ITypeMap map)
types[i - startBound] = reader.GetFieldType(i);
}
var ctor = typeMap.FindConstructor(names, types);
if (ctor == null)
var explicitConstr = typeMap.FindExplicitConstructor();
if (explicitConstr != null)
{
string proposedTypes = "(" + string.Join(", ", types.Select((t, i) => t.FullName + " " + names[i]).ToArray()) + ")";
throw new InvalidOperationException(string.Format("A parameterless default constructor or one matching signature {0} is required for {1} materialization", proposedTypes, type.FullName));
}
var structLocals = new Dictionary<Type, LocalBuilder>();
if (ctor.GetParameters().Length == 0)
{
il.Emit(OpCodes.Newobj, ctor);
var consPs = explicitConstr.GetParameters();
foreach(var p in consPs)
{
if(!p.ParameterType.IsValueType)
{
il.Emit(OpCodes.Ldnull);
}
else
{
LocalBuilder loc;
if(!structLocals.TryGetValue(p.ParameterType, out loc))
{
structLocals[p.ParameterType] = loc = il.DeclareLocal(p.ParameterType);
}
il.Emit(OpCodes.Ldloca, (short)loc.LocalIndex);
il.Emit(OpCodes.Initobj, p.ParameterType);
il.Emit(OpCodes.Ldloca, (short)loc.LocalIndex);
il.Emit(OpCodes.Ldobj, p.ParameterType);
}
}
il.Emit(OpCodes.Newobj, explicitConstr);
il.Emit(OpCodes.Stloc_1);
supportInitialize = typeof(ISupportInitialize).IsAssignableFrom(type);
if(supportInitialize)
if (supportInitialize)
{
il.Emit(OpCodes.Ldloc_1);
il.EmitCall(OpCodes.Callvirt, typeof(ISupportInitialize).GetMethod("BeginInit"), null);
}
}
else
specializedConstructor = ctor;
{
var ctor = typeMap.FindConstructor(names, types);
if (ctor == null)
{
string proposedTypes = "(" + string.Join(", ", types.Select((t, i) => t.FullName + " " + names[i]).ToArray()) + ")";
throw new InvalidOperationException(string.Format("A parameterless default constructor or one matching signature {0} is required for {1} materialization", proposedTypes, type.FullName));
}
if (ctor.GetParameters().Length == 0)
{
il.Emit(OpCodes.Newobj, ctor);
il.Emit(OpCodes.Stloc_1);
supportInitialize = typeof(ISupportInitialize).IsAssignableFrom(type);
if (supportInitialize)
{
il.Emit(OpCodes.Ldloc_1);
il.EmitCall(OpCodes.Callvirt, typeof(ISupportInitialize).GetMethod("BeginInit"), null);
}
}
else
{
specializedConstructor = ctor;
}
}
}
il.BeginExceptionBlock();
......@@ -5216,6 +5266,22 @@ public ConstructorInfo FindConstructor(string[] names, Type[] types)
return null;
}
/// <summary>
/// Returns the constructor, if any, that has the ExplicitConstructorAttribute on it.
/// </summary>
public ConstructorInfo FindExplicitConstructor()
{
var constructors = _type.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
var withAttr = constructors.Where(c => c.GetCustomAttributes(typeof(ExplicitConstructorAttribute), true).Length > 0).ToList();
if (withAttr.Count == 1)
{
return withAttr[0];
}
return null;
}
/// <summary>
/// Gets mapping for constructor parameter
/// </summary>
......@@ -5306,6 +5372,15 @@ public ConstructorInfo FindConstructor(string[] names, Type[] types)
return _type.GetConstructor(new Type[0]);
}
/// <summary>
/// Always returns null
/// </summary>
/// <returns></returns>
public ConstructorInfo FindExplicitConstructor()
{
return null;
}
/// <summary>
/// Not impelmeneted as far as default constructor used for all cases
/// </summary>
......@@ -5544,6 +5619,15 @@ public interface IWrappedDataReader : IDataReader
IDbCommand Command { get; }
}
/// <summary>
/// Tell Dapper to use an explicit constructor, passing nulls or 0s for all parameters
/// </summary>
[AttributeUsage(AttributeTargets.Constructor, AllowMultiple = false)]
public sealed class ExplicitConstructorAttribute : Attribute
{
}
// Define DAPPER_MAKE_PRIVATE if you reference Dapper by source
// and you like to make the Dapper types private (in order to avoid
// conflicts with other projects that also reference Dapper by source)
......
......@@ -4086,6 +4086,43 @@ public void Issue192_InParameterWorksWithSimilarNamesWithUnicode()
((int)rows.Field).IsEqualTo(2);
((int)rows.Field_1).IsEqualTo(2);
}
class _ExplicitConstructors
{
public int Field { get; set; }
public int Field_1 { get; set; }
private bool WentThroughProperConstructor;
public _ExplicitConstructors() { }
[ExplicitConstructor]
public _ExplicitConstructors(string foo, int bar)
{
WentThroughProperConstructor = true;
}
public bool GetWentThroughProperConstructor()
{
return WentThroughProperConstructor;
}
}
public void ExplicitConstructors()
{
var rows = connection.Query<_ExplicitConstructors>(@"
declare @ExplicitConstructors table (
Field INT NOT NULL PRIMARY KEY IDENTITY(1,1),
Field_1 INT NOT NULL);
insert @ExplicitConstructors(Field_1) values (1);
SELECT * FROM @ExplicitConstructors"
).ToList();
rows.Count.IsEqualTo(1);
rows[0].Field.IsEqualTo(1);
rows[0].Field_1.IsEqualTo(1);
rows[0].GetWentThroughProperConstructor().IsTrue();
}
#if POSTGRESQL
class Cat
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册