Skip to content
This repository was archived by the owner on Dec 24, 2022. It is now read-only.

Commit b317b87

Browse files
committed
Add Generic GetPropertyGetterFn<T> and GetFieldGetterFn<T> inc Expr + IL impls
1 parent 92d6767 commit b317b87

File tree

5 files changed

+191
-45
lines changed

5 files changed

+191
-45
lines changed

src/ServiceStack.Text/PclExport.Net40.cs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,17 @@ public override GetMemberDelegate GetPropertyGetterFn(PropertyInfo propertyInfo)
300300
: base.GetPropertyGetterFn(propertyInfo);
301301
}
302302

303+
public override GetMemberDelegate<T> GetPropertyGetterFn<T>(PropertyInfo propertyInfo)
304+
{
305+
return
306+
#if NET45
307+
SupportsEmit ? PropertyInvoker.GetEmit<T>(propertyInfo) :
308+
#endif
309+
SupportsExpression
310+
? PropertyInvoker.GetExpression<T>(propertyInfo)
311+
: base.GetPropertyGetterFn<T>(propertyInfo);
312+
}
313+
303314
public override SetMemberDelegate GetPropertySetterFn(PropertyInfo propertyInfo)
304315
{
305316
return
@@ -322,6 +333,17 @@ public override GetMemberDelegate GetFieldGetterFn(FieldInfo fieldInfo)
322333
: base.GetFieldGetterFn(fieldInfo);
323334
}
324335

336+
public override GetMemberDelegate<T> GetFieldGetterFn<T>(FieldInfo fieldInfo)
337+
{
338+
return
339+
#if NET45
340+
SupportsEmit ? FieldInvoker.GetEmit<T>(fieldInfo) :
341+
#endif
342+
SupportsExpression
343+
? FieldInvoker.GetExpression<T>(fieldInfo)
344+
: base.GetFieldGetterFn<T>(fieldInfo);
345+
}
346+
325347
public override SetMemberDelegate GetFieldSetterFn(FieldInfo fieldInfo)
326348
{
327349
return

src/ServiceStack.Text/PclExport.NetStandard.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,15 @@ public override GetMemberDelegate GetPropertyGetterFn(PropertyInfo propertyInfo)
300300
: base.GetPropertyGetterFn(propertyInfo);
301301
}
302302

303+
public override GetMemberDelegate<T> GetPropertyGetterFn<T>(PropertyInfo propertyInfo)
304+
{
305+
return SupportsEmit
306+
? PropertyInvoker.GetEmit<T>(propertyInfo)
307+
: SupportsExpression
308+
? PropertyInvoker.GetExpression<T>(propertyInfo)
309+
: base.GetPropertyGetterFn<T>(propertyInfo);
310+
}
311+
303312
public override SetMemberDelegate GetPropertySetterFn(PropertyInfo propertyInfo)
304313
{
305314
return SupportsEmit
@@ -318,6 +327,15 @@ public override GetMemberDelegate GetFieldGetterFn(FieldInfo fieldInfo)
318327
: base.GetFieldGetterFn(fieldInfo);
319328
}
320329

330+
public override GetMemberDelegate<T> GetFieldGetterFn<T>(FieldInfo fieldInfo)
331+
{
332+
return SupportsEmit
333+
? FieldInvoker.GetEmit<T>(fieldInfo)
334+
: SupportsExpression
335+
? FieldInvoker.GetExpression<T>(fieldInfo)
336+
: base.GetFieldGetterFn<T>(fieldInfo);
337+
}
338+
321339
public override SetMemberDelegate GetFieldSetterFn(FieldInfo fieldInfo)
322340
{
323341
return SupportsEmit

src/ServiceStack.Text/PclExport.cs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,11 @@ public virtual GetMemberDelegate GetFieldGetterFn(FieldInfo fieldInfo)
336336
return fieldInfo.GetValue;
337337
}
338338

339+
public virtual GetMemberDelegate<T> GetFieldGetterFn<T>(FieldInfo fieldInfo)
340+
{
341+
return x => fieldInfo.GetValue(x);
342+
}
343+
339344
public virtual SetMemberDelegate GetSetMethod(PropertyInfo propertyInfo, FieldInfo fieldInfo)
340345
{
341346
if (propertyInfo.CanWrite)
@@ -381,7 +386,15 @@ public virtual GetMemberDelegate GetPropertyGetterFn(PropertyInfo propertyInfo)
381386
var getMethodInfo = propertyInfo.GetMethodInfo();
382387
if (getMethodInfo == null) return null;
383388

384-
return o => propertyInfo.GetMethodInfo().Invoke(o, new object[] { });
389+
return o => propertyInfo.GetMethodInfo().Invoke(o, TypeConstants.EmptyObjectArray);
390+
}
391+
392+
public virtual GetMemberDelegate<T> GetPropertyGetterFn<T>(PropertyInfo propertyInfo)
393+
{
394+
var getMethodInfo = propertyInfo.GetMethodInfo();
395+
if (getMethodInfo == null) return null;
396+
397+
return o => propertyInfo.GetMethodInfo().Invoke(o, TypeConstants.EmptyObjectArray);
385398
}
386399

387400
public virtual string ToXsdDateTimeString(DateTime dateTime)

src/ServiceStack.Text/TypeFields.cs

Lines changed: 57 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,9 @@ public static class FieldInvoker
156156
public static GetMemberDelegate GetFieldGetterFn(this FieldInfo fieldInfo) =>
157157
PclExport.Instance.GetFieldGetterFn(fieldInfo);
158158

159+
public static GetMemberDelegate<T> GetFieldGetterFn<T>(this FieldInfo fieldInfo) =>
160+
PclExport.Instance.GetFieldGetterFn<T>(fieldInfo);
161+
159162
public static SetMemberDelegate GetFieldSetterFn(this FieldInfo fieldInfo) =>
160163
PclExport.Instance.GetFieldSetterFn(fieldInfo);
161164

@@ -172,33 +175,35 @@ internal static void SetField<TValue>(ref TValue field, TValue newValue)
172175
}
173176

174177
#if (!NETSTANDARD1_1 || NETSTANDARD1_3)
178+
public static GetMemberDelegate<T> GetExpression<T>(FieldInfo fieldInfo)
179+
{
180+
var instance = Expression.Parameter(typeof(T), "i");
181+
var field = typeof(T) != fieldInfo.DeclaringType
182+
? Expression.Field(Expression.TypeAs(instance, fieldInfo.DeclaringType), fieldInfo)
183+
: Expression.Field(instance, fieldInfo);
184+
var convertField = Expression.TypeAs(field, typeof(object));
185+
return Expression.Lambda<GetMemberDelegate<T>>(convertField, instance).Compile();
186+
}
187+
175188
public static GetMemberDelegate GetExpression(FieldInfo fieldInfo)
176189
{
177-
try
178-
{
179-
var fieldDeclaringType = fieldInfo.DeclaringType;
190+
var fieldDeclaringType = fieldInfo.DeclaringType;
180191

181-
var oInstanceParam = Expression.Parameter(typeof(object), "source");
182-
var instanceParam = GetCastOrConvertExpression(oInstanceParam, fieldDeclaringType);
192+
var oInstanceParam = Expression.Parameter(typeof(object), "source");
193+
var instanceParam = GetCastOrConvertExpression(oInstanceParam, fieldDeclaringType);
183194

184-
var exprCallFieldGetFn = Expression.Field(instanceParam, fieldInfo);
185-
//var oExprCallFieldGetFn = this.GetCastOrConvertExpression(exprCallFieldGetFn, typeof(object));
186-
var oExprCallFieldGetFn = Expression.Convert(exprCallFieldGetFn, typeof(object));
195+
var exprCallFieldGetFn = Expression.Field(instanceParam, fieldInfo);
196+
//var oExprCallFieldGetFn = this.GetCastOrConvertExpression(exprCallFieldGetFn, typeof(object));
197+
var oExprCallFieldGetFn = Expression.Convert(exprCallFieldGetFn, typeof(object));
187198

188-
var fieldGetterFn = Expression.Lambda<GetMemberDelegate>
189-
(
190-
oExprCallFieldGetFn,
191-
oInstanceParam
192-
)
193-
.Compile();
199+
var fieldGetterFn = Expression.Lambda<GetMemberDelegate>
200+
(
201+
oExprCallFieldGetFn,
202+
oInstanceParam
203+
)
204+
.Compile();
194205

195-
return fieldGetterFn;
196-
}
197-
catch (Exception ex)
198-
{
199-
Tracer.Instance.WriteError(ex);
200-
throw;
201-
}
206+
return fieldGetterFn;
202207
}
203208

204209
public static SetMemberDelegate SetExpression(FieldInfo fieldInfo)
@@ -252,6 +257,26 @@ private static Expression GetCastOrConvertExpression(Expression expression, Type
252257
#endif
253258

254259
#if NET45 || NETSTANDARD1_3
260+
public static GetMemberDelegate<T> GetEmit<T>(FieldInfo fieldInfo)
261+
{
262+
var getter = CreateDynamicGetMethod<T>(fieldInfo);
263+
264+
var gen = getter.GetILGenerator();
265+
266+
gen.Emit(OpCodes.Ldarg_0);
267+
268+
gen.Emit(OpCodes.Ldfld, fieldInfo);
269+
270+
if (fieldInfo.FieldType.IsValueType())
271+
{
272+
gen.Emit(OpCodes.Box, fieldInfo.FieldType);
273+
}
274+
275+
gen.Emit(OpCodes.Ret);
276+
277+
return (GetMemberDelegate<T>)getter.CreateDelegate(typeof(GetMemberDelegate<T>));
278+
}
279+
255280
public static GetMemberDelegate GetEmit(FieldInfo fieldInfo)
256281
{
257282
var getter = CreateDynamicGetMethod(fieldInfo);
@@ -294,6 +319,17 @@ internal static DynamicMethod CreateDynamicGetMethod(MemberInfo memberInfo)
294319
: new DynamicMethod(name, returnType, DynamicGetMethodArgs, memberInfo.Module, true);
295320
}
296321

322+
internal static DynamicMethod CreateDynamicGetMethod<T>(MemberInfo memberInfo)
323+
{
324+
var memberType = memberInfo is FieldInfo ? "Field" : "Property";
325+
var name = $"_Get{memberType}[T]_{memberInfo.Name}_";
326+
var returnType = typeof(object);
327+
328+
return !memberInfo.DeclaringType.IsInterface()
329+
? new DynamicMethod(name, returnType, new[] { typeof(T) }, memberInfo.DeclaringType, true)
330+
: new DynamicMethod(name, returnType, new[] { typeof(T) }, memberInfo.Module, true);
331+
}
332+
297333
public static SetMemberDelegate SetEmit(FieldInfo fieldInfo)
298334
{
299335
var setter = CreateDynamicSetMethod(fieldInfo);

src/ServiceStack.Text/TypeProperties.cs

Lines changed: 80 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,9 @@ public static class PropertyInvoker
138138
public static GetMemberDelegate GetPropertyGetterFn(this PropertyInfo propertyInfo) =>
139139
PclExport.Instance.GetPropertyGetterFn(propertyInfo);
140140

141+
public static GetMemberDelegate<T> GetPropertyGetterFn<T>(this PropertyInfo propertyInfo) =>
142+
PclExport.Instance.GetPropertyGetterFn<T>(propertyInfo);
143+
141144
public static SetMemberDelegate GetPropertySetterFn(this PropertyInfo propertyInfo) =>
142145
PclExport.Instance.GetPropertySetterFn(propertyInfo);
143146

@@ -146,32 +149,45 @@ public static SetMemberDelegate GetPropertySetterFn(this PropertyInfo propertyIn
146149
public static SetMemberDelegate SetReflection(PropertyInfo propertyInfo) => propertyInfo.SetValue;
147150

148151
#if !NETSTANDARD1_1 || NETSTANDARD1_3
152+
public static GetMemberDelegate<T> GetExpression<T>(PropertyInfo propertyInfo)
153+
{
154+
var expr = GetExpressionLambda<T>(propertyInfo);
155+
return expr.Compile();
156+
}
157+
158+
public static Expression<GetMemberDelegate<T>> GetExpressionLambda<T>(PropertyInfo propertyInfo)
159+
{
160+
var instance = Expression.Parameter(typeof(T), "i");
161+
var property = typeof(T) != propertyInfo.DeclaringType
162+
? Expression.Property(Expression.TypeAs(instance, propertyInfo.DeclaringType), propertyInfo)
163+
: Expression.Property(instance, propertyInfo);
164+
var convertProperty = Expression.TypeAs(property, typeof(object));
165+
return Expression.Lambda<GetMemberDelegate<T>>(convertProperty, instance);
166+
}
167+
149168
public static GetMemberDelegate GetExpression(PropertyInfo propertyInfo)
169+
{
170+
var lambda = GetExpressionLambda(propertyInfo);
171+
var propertyGetFn = lambda.Compile();
172+
return propertyGetFn;
173+
}
174+
175+
public static Expression<GetMemberDelegate> GetExpressionLambda(PropertyInfo propertyInfo)
150176
{
151177
var getMethodInfo = propertyInfo.GetMethodInfo();
152178
if (getMethodInfo == null) return null;
153-
try
154-
{
155-
var oInstanceParam = Expression.Parameter(typeof(object), "oInstanceParam");
156-
var instanceParam = Expression.Convert(oInstanceParam, propertyInfo.ReflectedType()); //propertyInfo.DeclaringType doesn't work on Proxy types
157179

158-
var exprCallPropertyGetFn = Expression.Call(instanceParam, getMethodInfo);
159-
var oExprCallPropertyGetFn = Expression.Convert(exprCallPropertyGetFn, typeof(object));
180+
var oInstanceParam = Expression.Parameter(typeof(object), "oInstanceParam");
181+
var instanceParam = Expression.Convert(oInstanceParam, propertyInfo.ReflectedType()); //propertyInfo.DeclaringType doesn't work on Proxy types
160182

161-
var propertyGetFn = Expression.Lambda<GetMemberDelegate>
162-
(
163-
oExprCallPropertyGetFn,
164-
oInstanceParam
165-
).Compile();
183+
var exprCallPropertyGetFn = Expression.Call(instanceParam, getMethodInfo);
184+
var oExprCallPropertyGetFn = Expression.Convert(exprCallPropertyGetFn, typeof(object));
166185

167-
return propertyGetFn;
168-
169-
}
170-
catch (Exception ex)
171-
{
172-
Tracer.Instance.WriteError(ex);
173-
throw;
174-
}
186+
return Expression.Lambda<GetMemberDelegate>
187+
(
188+
oExprCallPropertyGetFn,
189+
oInstanceParam
190+
);
175191
}
176192

177193
public static SetMemberDelegate SetExpression(PropertyInfo propertyInfo)
@@ -200,6 +216,46 @@ public static SetMemberDelegate SetExpression(PropertyInfo propertyInfo)
200216
#endif
201217

202218
#if NET45 || NETSTANDARD1_3
219+
public static GetMemberDelegate<T> GetEmit<T>(PropertyInfo propertyInfo)
220+
{
221+
var getter = FieldInvoker.CreateDynamicGetMethod<T>(propertyInfo);
222+
223+
var gen = getter.GetILGenerator();
224+
var mi = propertyInfo.GetGetMethod(true);
225+
226+
if (typeof(T).IsValueType())
227+
{
228+
gen.Emit(OpCodes.Ldarga_S, 0);
229+
230+
if (typeof(T) != propertyInfo.DeclaringType)
231+
{
232+
gen.Emit(OpCodes.Unbox, propertyInfo.DeclaringType);
233+
}
234+
}
235+
else
236+
{
237+
gen.Emit(OpCodes.Ldarg_0);
238+
239+
if (typeof(T) != propertyInfo.DeclaringType)
240+
{
241+
gen.Emit(OpCodes.Castclass, propertyInfo.DeclaringType);
242+
}
243+
}
244+
245+
gen.Emit(mi.IsFinal ? OpCodes.Call : OpCodes.Callvirt, mi);
246+
247+
if (propertyInfo.PropertyType.IsValueType())
248+
{
249+
gen.Emit(OpCodes.Box, propertyInfo.PropertyType);
250+
}
251+
252+
gen.Emit(OpCodes.Isinst, typeof(object));
253+
254+
gen.Emit(OpCodes.Ret);
255+
256+
return (GetMemberDelegate<T>)getter.CreateDelegate(typeof(GetMemberDelegate<T>));
257+
}
258+
203259
public static GetMemberDelegate GetEmit(PropertyInfo propertyInfo)
204260
{
205261
var getter = FieldInvoker.CreateDynamicGetMethod(propertyInfo);
@@ -217,7 +273,7 @@ public static GetMemberDelegate GetEmit(PropertyInfo propertyInfo)
217273
}
218274

219275
var mi = propertyInfo.GetGetMethod(true);
220-
gen.Emit(OpCodes.Callvirt, mi);
276+
gen.Emit(mi.IsFinal ? OpCodes.Call : OpCodes.Callvirt, mi);
221277

222278
if (propertyInfo.PropertyType.IsValueType())
223279
{
@@ -231,8 +287,8 @@ public static GetMemberDelegate GetEmit(PropertyInfo propertyInfo)
231287

232288
public static SetMemberDelegate SetEmit(PropertyInfo propertyInfo)
233289
{
234-
var propSetMethod = propertyInfo.GetSetMethod(true);
235-
if (propSetMethod == null)
290+
var mi = propertyInfo.GetSetMethod(true);
291+
if (mi == null)
236292
return null;
237293

238294
var setter = FieldInvoker.CreateDynamicSetMethod(propertyInfo);
@@ -260,7 +316,8 @@ public static SetMemberDelegate SetEmit(PropertyInfo propertyInfo)
260316
gen.Emit(OpCodes.Castclass, propertyInfo.PropertyType);
261317
}
262318

263-
gen.EmitCall(OpCodes.Callvirt, propSetMethod, (Type[])null);
319+
gen.EmitCall(mi.IsFinal ? OpCodes.Call : OpCodes.Callvirt, mi, (Type[])null);
320+
264321
gen.Emit(OpCodes.Ret);
265322

266323
return (SetMemberDelegate)setter.CreateDelegate(typeof(SetMemberDelegate));

0 commit comments

Comments
 (0)