Commit be15592b authored by mgravell's avatar mgravell

special case handling for char

parent 2ebf5bf7
......@@ -828,6 +828,24 @@ IEnumerator IEnumerable.GetEnumerator()
};
}
#endif
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
[Obsolete("This method is for internal usage only", false)]
public static char ReadChar(object value)
{
if (value == null || value is DBNull) throw new ArgumentNullException("value");
string s = value as string;
if (s == null || s.Length != 1) throw new ArgumentException("A single-character was expected", "value");
return s[0];
}
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
[Obsolete("This method is for internal usage only", false)]
public static char? ReadNullableChar(object value)
{
if (value == null || value is DBNull) return null;
string s = value as string;
if (s == null || s.Length != 1) throw new ArgumentException("A single-character was expected", "value");
return s[0];
}
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
[Obsolete("This method is for internal usage only", true)]
public static void PackListParameters(IDbCommand command, string namePrefix, object value)
......@@ -1065,6 +1083,17 @@ private static int ExecuteCommand(IDbConnection cnn, IDbTransaction tranaction,
private static Func<IDataReader, T> GetStructDeserializer<T>(int index)
{
// no point using special per-type handling here; it boils down to the same, plus not all are supported anyway (see: SqlDataReader.GetChar - not supported!)
#pragma warning disable 618
if (typeof(T) == typeof(char))
{ // this *does* need special handling, though
return (Func<IDataReader, T>)(object)new Func<IDataReader, char>(r => SqlMapper.ReadChar(r.GetValue(index)));
}
if (typeof(T) == typeof(char?))
{
return (Func<IDataReader, T>)(object)new Func<IDataReader, char?>(r => SqlMapper.ReadNullableChar(r.GetValue(index)));
}
#pragma warning restore 618
return r =>
{
var val = r.GetValue(index);
......@@ -1151,12 +1180,21 @@ static readonly MethodInfo
il.Emit(OpCodes.Callvirt, getItem); // stack is now [target][target][value-as-object]
Type memberType = item.Property != null ? item.Property.Type : item.Field.FieldType;
if (memberType == typeof(char) || memberType == typeof(char?))
{
il.EmitCall(OpCodes.Call, typeof(SqlMapper).GetMethod(
memberType == typeof(char) ? "ReadChar" : "ReadNullableChar", BindingFlags.Static | BindingFlags.Public), null); // stack is now [target][target][typed-value]
}
else
{
il.Emit(OpCodes.Dup); // stack is now [target][target][value][value]
il.Emit(OpCodes.Isinst, typeof(DBNull)); // stack is now [target][target][value-as-object][DBNull or null]
il.Emit(OpCodes.Brtrue_S, isDbNullLabel); // stack is now [target][target][value-as-object]
// unbox nullable enums as the primitive, i.e. byte etc
Type memberType = item.Property != null ? item.Property.Type : item.Field.FieldType;
var nullUnderlyingType = Nullable.GetUnderlyingType(memberType);
var unboxType = nullUnderlyingType != null && nullUnderlyingType.IsEnum ? nullUnderlyingType : memberType;
......@@ -1208,6 +1246,7 @@ static readonly MethodInfo
{
il.Emit(OpCodes.Newobj, memberType.GetConstructor(new[] { nullUnderlyingType }));
}
}
if (item.Property != null)
{
il.Emit(OpCodes.Callvirt, item.Property.Setter); // stack is now [target]
......
......@@ -919,5 +919,44 @@ public void TestUnexpectedButFilteredDataMessage()
i.IsEqualTo(23);
}
class WithCharValue
{
public char Value { get; set; }
public char? ValueNullable { get; set; }
}
public void TestCharInputAndOutput()
{
const char test = '〠';
char c = connection.Query<char>("select @c", new { c = test }).Single();
c.IsEqualTo(test);
var obj = connection.Query<WithCharValue>("select @Value as Value", new WithCharValue { Value = c }).Single();
obj.Value.IsEqualTo(test);
}
public void TestNullableCharInputAndOutputNonNull()
{
char? test = '〠';
char? c = connection.Query<char?>("select @c", new { c = test }).Single();
c.IsEqualTo(test);
var obj = connection.Query<WithCharValue>("select @ValueNullable as ValueNullable", new WithCharValue { ValueNullable = c }).Single();
obj.ValueNullable.IsEqualTo(test);
}
public void TestNullableCharInputAndOutputNull()
{
char? test = null;
char? c = connection.Query<char?>("select @c", new { c = test }).Single();
c.IsEqualTo(test);
var obj = connection.Query<WithCharValue>("select @ValueNullable as ValueNullable", new WithCharValue { ValueNullable = c }).Single();
obj.ValueNullable.IsEqualTo(test);
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment