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

Commit 89fbeef

Browse files
committed
Make property cache key unique per generic type
1 parent acecaa3 commit 89fbeef

File tree

1 file changed

+40
-9
lines changed

1 file changed

+40
-9
lines changed

src/ServiceStack.Text/Reflection/StaticAccessors.cs

Lines changed: 40 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
//
1212
using System;
1313
using System.Collections.Generic;
14+
using System.Linq;
1415
using System.Reflection;
1516
using System.Threading;
1617
using ServiceStack.Text;
@@ -26,12 +27,16 @@ public static class StaticAccessors
2627

2728
public static Func<object, object> GetFastGetter(this Type type, string propName)
2829
{
29-
var key = $"{type.Namespace}.{type.Name}::{propName}";
30+
var key = GetTypePropertyKey(type, propName);
3031
Func<object, object> fn;
3132
if (getterFnCache.TryGetValue(key, out fn))
3233
return fn;
3334

34-
fn = GetValueGetter(type.GetPropertyInfo(propName));
35+
var pi = type.GetPropertyInfo(propName);
36+
if (pi == null)
37+
return null;
38+
39+
fn = GetValueGetter(pi);
3540

3641
Dictionary<string, Func<object, object>> snapshot, newCache;
3742
do
@@ -45,16 +50,42 @@ public static Func<object, object> GetFastGetter(this Type type, string propName
4550
return fn;
4651
}
4752

53+
private static string GetTypePropertyKey(Type type, string propName)
54+
{
55+
var key = StringBuilderThreadStatic.Allocate()
56+
.Append($"{type.Namespace}.{type.Name}::{propName}");
57+
58+
if (type.IsGenericType())
59+
{
60+
key.Append("<");
61+
var i = 0;
62+
foreach (var arg in type.GetGenericArguments())
63+
{
64+
if (i++ > 0)
65+
key.Append(",");
66+
67+
key.Append($"{arg.Namespace}.{arg.Name}");
68+
}
69+
key.Append(">");
70+
}
71+
72+
return StringBuilderThreadStatic.ReturnAndFree(key);
73+
}
74+
4875
private static Dictionary<string, Action<object, object>> setterFnCache = new Dictionary<string, Action<object, object>>();
4976

5077
public static Action<object, object> GetFastSetter(this Type type, string propName)
5178
{
52-
var key = $"{type.Namespace}.{type.Name}::{propName}";
79+
var key = GetTypePropertyKey(type, propName);
5380
Action<object, object> fn;
5481
if (setterFnCache.TryGetValue(key, out fn))
5582
return fn;
5683

57-
fn = GetValueSetter(type.GetPropertyInfo(propName));
84+
var pi = type.GetPropertyInfo(propName);
85+
if (pi == null)
86+
return null;
87+
88+
fn = GetValueSetter(pi);
5889

5990
Dictionary<string, Action<object, object>> snapshot, newCache;
6091
do
@@ -86,7 +117,7 @@ public static Func<object, object> GetValueGetter(this PropertyInfo propertyInfo
86117
#else
87118

88119
var instance = Expression.Parameter(typeof(object), "i");
89-
var convertInstance = Expression.TypeAs(instance, propertyInfo.DeclaringType);
120+
var convertInstance = Expression.TypeAs(instance, type);
90121
var property = Expression.Property(convertInstance, propertyInfo);
91122
var convertProperty = Expression.TypeAs(property, typeof(object));
92123
return Expression.Lambda<Func<object, object>>(convertProperty, instance).Compile();
@@ -129,17 +160,17 @@ public static Func<T, object> GetValueGetter<T>(this FieldInfo fieldInfo)
129160
}
130161

131162
#if !XBOX
132-
public static Action<object, object> GetValueSetter(this PropertyInfo propertyInfo, Type instanceType)
163+
public static Action<object, object> GetValueSetter(this PropertyInfo propertyInfo)
133164
{
134-
return GetValueSetter(propertyInfo);
165+
return GetValueSetter(propertyInfo, propertyInfo.DeclaringType);
135166
}
136167

137-
public static Action<object, object> GetValueSetter(this PropertyInfo propertyInfo)
168+
public static Action<object, object> GetValueSetter(this PropertyInfo propertyInfo, Type instanceType)
138169
{
139170
var instance = Expression.Parameter(typeof(object), "i");
140171
var argument = Expression.Parameter(typeof(object), "a");
141172

142-
var type = (Expression)Expression.TypeAs(instance, propertyInfo.DeclaringType);
173+
var type = (Expression)Expression.TypeAs(instance, instanceType);
143174

144175
var setterCall = Expression.Call(
145176
type,

0 commit comments

Comments
 (0)