Skip to content

Commit 5da5e3e

Browse files
committed
Fix NRE for annotated non-public members in WinRT.
This commit fixes same issue as previous unit-testing issue that GetRuntimeXxx (singular) never returns non-public members, so null is returned for non-public members.
1 parent be5cf53 commit 5da5e3e

File tree

5 files changed

+123
-9
lines changed

5 files changed

+123
-9
lines changed

CHANGES.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,3 +213,8 @@ Release 0.5.8 - 2015/1/18
213213
BUG FIXES
214214
* Fix Unpacker fails to unpack data when the stream returns data one by one. Issue #59
215215
* Fix Unpacker cannot read empty bytes from System.Net API. Issue #60
216+
217+
Relase 0.5.9 - 2015/2/01
218+
219+
BUG FIXES
220+
* Fix NullReferenceException is thrown for annotated non-public members serialization/deserialization in WinRT.

Sync.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@
7878
<Exclude Path="Serialization\Metadata\_DictionaryEntry.cs" />
7979
<Exclude Path="Serialization\Metadata\_IDisposable.cs" />
8080
<Exclude Path="Serialization\EmittingSerializers\*" />
81+
<Preserve Path="Serialization\Reflection\ReflectionHelpers.cs" />
8182
<Exclude Path="Serialization\IdentifierUtility.cs" />
8283
<Exclude Path="Serialization\ISerializerGeneratorConfiguration.cs" />
8384
<Exclude Path="Serialization\SerializerAssemblyGenerationConfiguration.cs" />
@@ -120,6 +121,7 @@
120121
<Project Name="MsgPack.Silverlight.WindowsPhone" Base="MsgPack.WinRT.Portable">
121122
<Preserve Path="Properties\AssemblyInfo.cs" />
122123
<Preserve Path="Serialization\Metadata\_DictionaryEntry.cs" />
124+
<Exclude Path="Serialization\Reflection\ReflectionHelpers.cs" />
123125
<Exclude Path="UnsafeNativeMethods.cs" />
124126
<Exclude Path="WinRTCompatibility.cs" />
125127
</Project>

src/MsgPack.WinRT.Portable/MsgPack.WinRT.Portable.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -626,6 +626,7 @@
626626
<Link>UnsafeNativeMethods.cs</Link>
627627
</Compile>
628628
<Compile Include="Properties\AssemblyInfo.cs" />
629+
<Compile Include="Serialization\Reflection\ReflectionHelpers.cs" />
629630
<Compile Include="WinRTCompatibility.cs" />
630631
</ItemGroup>
631632
<ItemGroup>
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
#region -- License Terms --
2+
//
3+
// NLiblet
4+
//
5+
// Copyright (C) 2015 FUJIWARA, Yusuke
6+
//
7+
// Licensed under the Apache License, Version 2.0 (the "License");
8+
// you may not use this file except in compliance with the License.
9+
// You may obtain a copy of the License at
10+
//
11+
// http://www.apache.org/licenses/LICENSE-2.0
12+
//
13+
// Unless required by applicable law or agreed to in writing, software
14+
// distributed under the License is distributed on an "AS IS" BASIS,
15+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
// See the License for the specific language governing permissions and
17+
// limitations under the License.
18+
//
19+
#endregion -- License Terms --
20+
21+
using System;
22+
using System.ComponentModel;
23+
using System.Linq;
24+
using System.Reflection;
25+
26+
namespace MsgPack.Serialization.Reflection
27+
{
28+
/// <summary>
29+
/// <strong>This is intened to MsgPack for CLI internal use. Do not use this type from application directly.</strong>
30+
/// Defines serialization helper APIs.
31+
/// </summary>
32+
[EditorBrowsable( EditorBrowsableState.Never )]
33+
public static class ReflectionHelpers
34+
{
35+
internal static readonly MethodInfo GetRuntimeMethodMethod =
36+
FromExpression.ToMethod(
37+
( Type source, string name, Type[] parameterTypes ) => GetRuntimeMethod( source, name, parameterTypes )
38+
);
39+
40+
/// <summary>
41+
/// Gets a specific method even if the candidate is not public.
42+
/// </summary>
43+
/// <param name="source">The target type.</param>
44+
/// <param name="name">The name of the method.</param>
45+
/// <param name="parameterTypes">The types of the parameter.</param>
46+
/// <returns>A <see cref="MethodInfo"/> if found; otherwise, <c>null</c>.</returns>
47+
/// <exception cref="ArgumentNullException"><paramref name="name"/> is <c>null</c>.</exception>
48+
/// <exception cref="ArgumentException"><paramref name="name"/> is empty.</exception>
49+
[EditorBrowsable( EditorBrowsableState.Never )]
50+
public static MethodInfo GetRuntimeMethod( this Type source, string name, params Type[] parameterTypes )
51+
{
52+
if ( name == null )
53+
{
54+
throw new ArgumentNullException( "name" );
55+
}
56+
57+
if ( name.Length == 0 )
58+
{
59+
throw new ArgumentException( "'name' cannot be empty.", "name" );
60+
}
61+
62+
var safeParameterTypes = parameterTypes ?? ReflectionAbstractions.EmptyTypes;
63+
64+
return
65+
source.GetRuntimeMethods()
66+
.SingleOrDefault(
67+
m => m.Name == name && m.GetParameters().Select( p => p.ParameterType ).SequenceEqual( safeParameterTypes )
68+
);
69+
}
70+
internal static readonly MethodInfo GetRuntimeFieldMethod =
71+
FromExpression.ToMethod(
72+
( Type source, string name ) => GetRuntimeField( source, name )
73+
);
74+
75+
/// <summary>
76+
/// Gets a specific field even if the candidate is not public.
77+
/// </summary>
78+
/// <param name="source">The target type.</param>
79+
/// <param name="name">The name of the method.</param>
80+
/// <returns>A <see cref="FieldInfo"/> if found; otherwise, <c>null</c>.</returns>
81+
/// <exception cref="ArgumentNullException"><paramref name="name"/> is <c>null</c>.</exception>
82+
/// <exception cref="ArgumentException"><paramref name="name"/> is empty.</exception>
83+
[EditorBrowsable( EditorBrowsableState.Never )]
84+
public static FieldInfo GetRuntimeField( this Type source, string name )
85+
{
86+
if ( name == null )
87+
{
88+
throw new ArgumentNullException( "name" );
89+
}
90+
91+
if ( name.Length == 0 )
92+
{
93+
throw new ArgumentException( "'name' cannot be empty.", "name" );
94+
}
95+
96+
return
97+
source.GetRuntimeFields()
98+
.SingleOrDefault(
99+
m => m.Name == name
100+
);
101+
}
102+
}
103+
}

src/MsgPack/Serialization/ExpressionSerializers/ExpressionTreeSerializerBuilder`1.cs

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//
33
// MessagePack for CLI
44
//
5-
// Copyright (C) 2010-2013 FUJIWARA, Yusuke
5+
// Copyright (C) 2010-2015 FUJIWARA, Yusuke
66
//
77
// Licensed under the Apache License, Version 2.0 (the "License");
88
// you may not use this file except in compliance with the License.
@@ -24,8 +24,13 @@
2424
using System.Linq;
2525
using System.Linq.Expressions;
2626
using System.Reflection;
27+
#if !NETFX_CORE
2728
using System.Reflection.Emit;
29+
#endif // !NETFX_CORE
2830
using MsgPack.Serialization.AbstractSerializers;
31+
#if NETFX_CORE
32+
using MsgPack.Serialization.Reflection;
33+
#endif // NETFX_CORE
2934

3035
namespace MsgPack.Serialization.ExpressionSerializers
3136
{
@@ -74,7 +79,7 @@ protected override void EmitMethodEpilogue( ExpressionTreeContext context, Seria
7479
return;
7580
}
7681

77-
context.SetDelegate( method, EmitMethodEpilogue( context, ExpressionTreeContext.CreateDelegateType<TObject>( method ), method, construct ) );
82+
context.SetDelegate( method, this.EmitMethodEpilogue( context, ExpressionTreeContext.CreateDelegateType<TObject>( method ), method, construct ) );
7883

7984
}
8085

@@ -85,7 +90,7 @@ protected override void EmitMethodEpilogue( ExpressionTreeContext context, EnumS
8590
return;
8691
}
8792

88-
context.SetDelegate( method, EmitMethodEpilogue( context, ExpressionTreeContext.CreateDelegateType<TObject>( method ), method, construct ) );
93+
context.SetDelegate( method, this.EmitMethodEpilogue( context, ExpressionTreeContext.CreateDelegateType<TObject>( method ), method, construct ) );
8994
}
9095

9196
#if NETFX_CORE || SILVERLIGHT
@@ -234,11 +239,10 @@ protected override ExpressionConstruct EmitMethodOfExpression( ExpressionTreeCon
234239
return Expression.Call( Metadata._MethodBase.GetMethodFromHandle, Expression.Constant( method.MethodHandle ) );
235240
#else
236241
// WinRT expression tree cannot handle Type constants, and MethodHandle property is not exposed.
237-
// Overloading is not supported.
238-
// typeof( T ).GetRuntimeMethod( method.Name, null );
242+
// typeof( T ).GetRuntimeMethod( method.Name, ...{types}... );
239243
return
240244
Expression.Call(
241-
typeof( RuntimeReflectionExtensions ).GetRuntimeMethod( "GetRuntimeMethod", new []{typeof(Type),typeof(string),typeof(Type[])} ),
245+
ReflectionHelpers.GetRuntimeMethodMethod,
242246
this.EmitTypeOfExpression( context, method.DeclaringType ).Expression,
243247
Expression.Constant( method.Name ),
244248
Expression.NewArrayInit(
@@ -264,11 +268,10 @@ protected override ExpressionConstruct EmitFieldOfExpression( ExpressionTreeCont
264268
return Expression.Call( Metadata._FieldInfo.GetFieldFromHandle, Expression.Constant( field.FieldHandle ) );
265269
#else
266270
// WinRT expression tree cannot handle Type constants, and MethodHandle property is not exposed.
267-
// Overloading is not supported.
268-
// typeof( T ).GetRuntimeField( field.Name, null );
271+
// typeof( T ).GetRuntimeField( field.Name );
269272
return
270273
Expression.Call(
271-
typeof( RuntimeReflectionExtensions ).GetRuntimeMethod( "GetRuntimeField", new[] { typeof( Type ), typeof( string ), typeof( Type[] ) } ),
274+
ReflectionHelpers.GetRuntimeFieldMethod,
272275
this.EmitTypeOfExpression( context, field.DeclaringType ).Expression,
273276
Expression.Constant( field.Name )
274277
);

0 commit comments

Comments
 (0)