Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
D
Dapper
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
tsai
Dapper
Commits
be15592b
Commit
be15592b
authored
Jul 04, 2011
by
mgravell
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
special case handling for char
parent
2ebf5bf7
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
121 additions
and
43 deletions
+121
-43
SqlMapper.cs
Dapper/SqlMapper.cs
+82
-43
Tests.cs
Tests/Tests.cs
+39
-0
No files found.
Dapper/SqlMapper.cs
View file @
be15592b
...
...
@@ -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,62 +1180,72 @@ static readonly MethodInfo
il
.
Emit
(
OpCodes
.
Callvirt
,
getItem
);
// stack is now [target][target][value-as-object]
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
;
if
(
unboxType
.
IsEnum
)
if
(
memberType
==
typeof
(
char
)
||
memberType
==
typeof
(
char
?)
)
{
if
(!
haveEnumLocal
)
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
var
nullUnderlyingType
=
Nullable
.
GetUnderlyingType
(
memberType
);
var
unboxType
=
nullUnderlyingType
!=
null
&&
nullUnderlyingType
.
IsEnum
?
nullUnderlyingType
:
memberType
;
if
(
unboxType
.
IsEnum
)
{
il
.
DeclareLocal
(
typeof
(
string
));
haveEnumLocal
=
true
;
}
if
(!
haveEnumLocal
)
{
il
.
DeclareLocal
(
typeof
(
string
));
haveEnumLocal
=
true
;
}
Label
isNotString
=
il
.
DefineLabel
();
il
.
Emit
(
OpCodes
.
Dup
);
// stack is now [target][target][value][value]
il
.
Emit
(
OpCodes
.
Isinst
,
typeof
(
string
));
// stack is now [target][target][value-as-object][string or null]
il
.
Emit
(
OpCodes
.
Dup
);
// stack is now [target][target][value-as-object][string or null][string or null]
il
.
Emit
(
OpCodes
.
Stloc_2
);
// stack is now [target][target][value-as-object][string or null]
il
.
Emit
(
OpCodes
.
Brfalse_S
,
isNotString
);
// stack is now [target][target][value-as-object]
Label
isNotString
=
il
.
DefineLabel
();
il
.
Emit
(
OpCodes
.
Dup
);
// stack is now [target][target][value][value]
il
.
Emit
(
OpCodes
.
Isinst
,
typeof
(
string
));
// stack is now [target][target][value-as-object][string or null]
il
.
Emit
(
OpCodes
.
Dup
);
// stack is now [target][target][value-as-object][string or null][string or null]
il
.
Emit
(
OpCodes
.
Stloc_2
);
// stack is now [target][target][value-as-object][string or null]
il
.
Emit
(
OpCodes
.
Brfalse_S
,
isNotString
);
// stack is now [target][target][value-as-object]
il
.
Emit
(
OpCodes
.
Pop
);
// stack is now [target][target]
il
.
Emit
(
OpCodes
.
Pop
);
// stack is now [target][target]
il
.
Emit
(
OpCodes
.
Ldtoken
,
unboxType
);
// stack is now [target][target][enum-type-token]
il
.
EmitCall
(
OpCodes
.
Call
,
typeof
(
Type
).
GetMethod
(
"GetTypeFromHandle"
),
null
);
// stack is now [target][target][enum-type]
il
.
Emit
(
OpCodes
.
Ldloc_2
);
// stack is now [target][target][enum-type][string]
il
.
Emit
(
OpCodes
.
Ldc_I4_1
);
// stack is now [target][target][enum-type][string][true]
il
.
EmitCall
(
OpCodes
.
Call
,
enumParse
,
null
);
// stack is now [target][target][enum-as-object]
il
.
Emit
(
OpCodes
.
Ldtoken
,
unboxType
);
// stack is now [target][target][enum-type-token]
il
.
EmitCall
(
OpCodes
.
Call
,
typeof
(
Type
).
GetMethod
(
"GetTypeFromHandle"
),
null
);
// stack is now [target][target][enum-type]
il
.
Emit
(
OpCodes
.
Ldloc_2
);
// stack is now [target][target][enum-type][string]
il
.
Emit
(
OpCodes
.
Ldc_I4_1
);
// stack is now [target][target][enum-type][string][true]
il
.
EmitCall
(
OpCodes
.
Call
,
enumParse
,
null
);
// stack is now [target][target][enum-as-object]
il
.
Emit
(
OpCodes
.
Unbox_Any
,
unboxType
);
// stack is now [target][target][typed-value]
il
.
Emit
(
OpCodes
.
Unbox_Any
,
unboxType
);
// stack is now [target][target][typed-value]
if
(
nullUnderlyingType
!=
null
)
{
il
.
Emit
(
OpCodes
.
Newobj
,
memberType
.
GetConstructor
(
new
[]
{
nullUnderlyingType
}));
}
if
(
item
.
Property
!=
null
)
{
il
.
Emit
(
OpCodes
.
Callvirt
,
item
.
Property
.
Setter
);
// stack is now [target]
if
(
nullUnderlyingType
!=
null
)
{
il
.
Emit
(
OpCodes
.
Newobj
,
memberType
.
GetConstructor
(
new
[]
{
nullUnderlyingType
}));
}
if
(
item
.
Property
!=
null
)
{
il
.
Emit
(
OpCodes
.
Callvirt
,
item
.
Property
.
Setter
);
// stack is now [target]
}
else
{
il
.
Emit
(
OpCodes
.
Stfld
,
item
.
Field
);
// stack is now [target]
}
il
.
Emit
(
OpCodes
.
Br_S
,
finishLabel
);
il
.
MarkLabel
(
isNotString
);
}
else
il
.
Emit
(
OpCodes
.
Unbox_Any
,
unboxType
);
// stack is now [target][target][typed-value]
if
(
nullUnderlyingType
!=
null
&&
nullUnderlyingType
.
IsEnum
)
{
il
.
Emit
(
OpCodes
.
Stfld
,
item
.
Field
);
// stack is now [target]
il
.
Emit
(
OpCodes
.
Newobj
,
memberType
.
GetConstructor
(
new
[]
{
nullUnderlyingType
}));
}
il
.
Emit
(
OpCodes
.
Br_S
,
finishLabel
);
il
.
MarkLabel
(
isNotString
);
}
il
.
Emit
(
OpCodes
.
Unbox_Any
,
unboxType
);
// stack is now [target][target][typed-value]
if
(
nullUnderlyingType
!=
null
&&
nullUnderlyingType
.
IsEnum
)
{
il
.
Emit
(
OpCodes
.
Newobj
,
memberType
.
GetConstructor
(
new
[]
{
nullUnderlyingType
}));
}
if
(
item
.
Property
!=
null
)
{
...
...
Tests/Tests.cs
View file @
be15592b
...
...
@@ -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
);
}
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment