blob: df820ca36bd8eb41d0f577c5508d09db7bf80b0b [file] [log] [blame]
Brian Silverman9c614bc2016-02-15 20:20:02 -05001#region Copyright notice and license
2// Protocol Buffers - Google's data interchange format
3// Copyright 2008 Google Inc. All rights reserved.
4// https://developers.google.com/protocol-buffers/
5//
6// Redistribution and use in source and binary forms, with or without
7// modification, are permitted provided that the following conditions are
8// met:
9//
10// * Redistributions of source code must retain the above copyright
11// notice, this list of conditions and the following disclaimer.
12// * Redistributions in binary form must reproduce the above
13// copyright notice, this list of conditions and the following disclaimer
14// in the documentation and/or other materials provided with the
15// distribution.
16// * Neither the name of Google Inc. nor the names of its
17// contributors may be used to endorse or promote products derived from
18// this software without specific prior written permission.
19//
20// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31#endregion
32
33using System;
34using System.Collections.Generic;
35using System.Linq.Expressions;
36using System.Reflection;
37
38namespace Google.Protobuf.Reflection
39{
40 /// <summary>
41 /// The methods in this class are somewhat evil, and should not be tampered with lightly.
42 /// Basically they allow the creation of relatively weakly typed delegates from MethodInfos
43 /// which are more strongly typed. They do this by creating an appropriate strongly typed
44 /// delegate from the MethodInfo, and then calling that within an anonymous method.
45 /// Mind-bending stuff (at least to your humble narrator) but the resulting delegates are
46 /// very fast compared with calling Invoke later on.
47 /// </summary>
48 internal static class ReflectionUtil
49 {
50 /// <summary>
51 /// Empty Type[] used when calling GetProperty to force property instead of indexer fetching.
52 /// </summary>
53 internal static readonly Type[] EmptyTypes = new Type[0];
54
55 /// <summary>
56 /// Creates a delegate which will cast the argument to the appropriate method target type,
57 /// call the method on it, then convert the result to object.
58 /// </summary>
59 internal static Func<IMessage, object> CreateFuncIMessageObject(MethodInfo method)
60 {
61 ParameterExpression parameter = Expression.Parameter(typeof(IMessage), "p");
62 Expression downcast = Expression.Convert(parameter, method.DeclaringType);
63 Expression call = Expression.Call(downcast, method);
64 Expression upcast = Expression.Convert(call, typeof(object));
65 return Expression.Lambda<Func<IMessage, object>>(upcast, parameter).Compile();
66 }
67
68 /// <summary>
69 /// Creates a delegate which will cast the argument to the appropriate method target type,
70 /// call the method on it, then convert the result to the specified type.
71 /// </summary>
72 internal static Func<IMessage, T> CreateFuncIMessageT<T>(MethodInfo method)
73 {
74 ParameterExpression parameter = Expression.Parameter(typeof(IMessage), "p");
75 Expression downcast = Expression.Convert(parameter, method.DeclaringType);
76 Expression call = Expression.Call(downcast, method);
77 Expression upcast = Expression.Convert(call, typeof(T));
78 return Expression.Lambda<Func<IMessage, T>>(upcast, parameter).Compile();
79 }
80
81 /// <summary>
82 /// Creates a delegate which will execute the given method after casting the first argument to
83 /// the target type of the method, and the second argument to the first parameter type of the method.
84 /// </summary>
85 internal static Action<IMessage, object> CreateActionIMessageObject(MethodInfo method)
86 {
87 ParameterExpression targetParameter = Expression.Parameter(typeof(IMessage), "target");
88 ParameterExpression argParameter = Expression.Parameter(typeof(object), "arg");
89 Expression castTarget = Expression.Convert(targetParameter, method.DeclaringType);
90 Expression castArgument = Expression.Convert(argParameter, method.GetParameters()[0].ParameterType);
91 Expression call = Expression.Call(castTarget, method, castArgument);
92 return Expression.Lambda<Action<IMessage, object>>(call, targetParameter, argParameter).Compile();
93 }
94
95 /// <summary>
96 /// Creates a delegate which will execute the given method after casting the first argument to
97 /// the target type of the method.
98 /// </summary>
99 internal static Action<IMessage> CreateActionIMessage(MethodInfo method)
100 {
101 ParameterExpression targetParameter = Expression.Parameter(typeof(IMessage), "target");
102 Expression castTarget = Expression.Convert(targetParameter, method.DeclaringType);
103 Expression call = Expression.Call(castTarget, method);
104 return Expression.Lambda<Action<IMessage>>(call, targetParameter).Compile();
105 }
106 }
107}