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

Commit b8edb83

Browse files
committed
Add field accessor and tests for set/get of sub and super fields/properties
1 parent f737a94 commit b8edb83

File tree

2 files changed

+89
-15
lines changed

2 files changed

+89
-15
lines changed

src/ServiceStack.Text/Reflection/StaticAccessors.cs

Lines changed: 39 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,12 @@ public static Func<T, object> GetValueGetter<T>(this PropertyInfo propertyInfo)
5151
if (getMethodInfo == null) return null;
5252
return x => getMethodInfo.Invoke(x, new object[0]);
5353
#else
54-
var instance = Expression.Parameter(propertyInfo.DeclaringType, "i");
55-
var property = Expression.Property(instance, propertyInfo);
56-
var convert = Expression.TypeAs(property, typeof(object));
57-
return Expression.Lambda<Func<T, object>>(convert, instance).Compile();
54+
var instance = Expression.Parameter(typeof(T), "i");
55+
var property = typeof(T) != propertyInfo.DeclaringType
56+
? Expression.Property(Expression.TypeAs(instance, propertyInfo.DeclaringType), propertyInfo)
57+
: Expression.Property(instance, propertyInfo);
58+
var convertProperty = Expression.TypeAs(property, typeof(object));
59+
return Expression.Lambda<Func<T, object>>(convertProperty, instance).Compile();
5860
#endif
5961
}
6062

@@ -63,25 +65,28 @@ public static Func<T, object> GetValueGetter<T>(this FieldInfo fieldInfo)
6365
#if (SL5 && !WP) || __IOS__ || XBOX
6466
return x => fieldInfo.GetValue(x);
6567
#else
66-
var instance = Expression.Parameter(fieldInfo.DeclaringType, "i");
67-
var property = Expression.Field(instance, fieldInfo);
68-
var convert = Expression.TypeAs(property, typeof(object));
69-
return Expression.Lambda<Func<T, object>>(convert, instance).Compile();
68+
69+
var instance = Expression.Parameter(typeof(T), "i");
70+
var field = typeof(T) != fieldInfo.DeclaringType
71+
? Expression.Field(Expression.TypeAs(instance, fieldInfo.DeclaringType), fieldInfo)
72+
: Expression.Field(instance, fieldInfo);
73+
var convertField = Expression.TypeAs(field, typeof(object));
74+
return Expression.Lambda<Func<T, object>>(convertField, instance).Compile();
7075
#endif
7176
}
7277

7378
#if !XBOX
7479
public static Action<T, object> GetValueSetter<T>(this PropertyInfo propertyInfo)
7580
{
76-
if (typeof(T) != propertyInfo.DeclaringType)
77-
{
78-
throw new ArgumentException();
79-
}
80-
81-
var instance = Expression.Parameter(propertyInfo.DeclaringType, "i");
81+
var instance = Expression.Parameter(typeof(T), "i");
8282
var argument = Expression.Parameter(typeof(object), "a");
83+
84+
var instanceType = typeof(T) != propertyInfo.DeclaringType
85+
? (Expression)Expression.TypeAs(instance, propertyInfo.DeclaringType)
86+
: instance;
87+
8388
var setterCall = Expression.Call(
84-
instance,
89+
instanceType,
8590
propertyInfo.SetMethod(),
8691
Expression.Convert(argument, propertyInfo.PropertyType));
8792

@@ -90,6 +95,25 @@ public static Action<T, object> GetValueSetter<T>(this PropertyInfo propertyInfo
9095
setterCall, instance, argument
9196
).Compile();
9297
}
98+
99+
public static Action<T, object> GetValueSetter<T>(this FieldInfo fieldInfo)
100+
{
101+
var instance = Expression.Parameter(typeof(T), "i");
102+
var argument = Expression.Parameter(typeof(object), "a");
103+
104+
var field = typeof(T) != fieldInfo.DeclaringType
105+
? Expression.Field(Expression.TypeAs(instance, fieldInfo.DeclaringType), fieldInfo)
106+
: Expression.Field(instance, fieldInfo);
107+
108+
var setterCall = Expression.Assign(
109+
field,
110+
Expression.Convert(argument, fieldInfo.FieldType));
111+
112+
return Expression.Lambda<Action<T, object>>
113+
(
114+
setterCall, instance, argument
115+
).Compile();
116+
}
93117
#endif
94118

95119
}

tests/ServiceStack.Text.Tests/StaticAccessorTests.cs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,21 @@ namespace ServiceStack.Text.Tests
66
public class AccessorBase
77
{
88
public string Base { get; set; }
9+
public string BaseField;
910
}
1011

1112
public class Accessor
1213
{
1314
public string Declared { get; set; }
1415
}
1516

17+
public class SubAccessor : AccessorBase
18+
{
19+
public string Sub { get; set; }
20+
public string SubField;
21+
}
22+
23+
1624
[TestFixture]
1725
public class StaticAccessorTests
1826
{
@@ -28,5 +36,47 @@ public void Can_get_accessor_in_declared_and_base_class()
2836
var declaredSetter = declaredProperty.GetValueSetter<Accessor>();
2937
Assert.That(declaredSetter, Is.Not.Null);
3038
}
39+
40+
[Test]
41+
public void Can_get_property_accessor_from_sub_and_super_types()
42+
{
43+
var sub = new SubAccessor();
44+
var subGet = StaticAccessors.GetValueGetter<SubAccessor>(typeof(SubAccessor).GetProperty("Sub"));
45+
var subSet = StaticAccessors.GetValueSetter<SubAccessor>(typeof(SubAccessor).GetProperty("Sub"));
46+
47+
subSet(sub, "sub");
48+
Assert.That(subGet(sub), Is.EqualTo("sub"));
49+
50+
var sup = new AccessorBase();
51+
var supGet = StaticAccessors.GetValueGetter<AccessorBase>(typeof(AccessorBase).GetProperty("Base"));
52+
var supSet = StaticAccessors.GetValueSetter<AccessorBase>(typeof(AccessorBase).GetProperty("Base"));
53+
54+
supSet(sup, "base");
55+
Assert.That(supGet(sup), Is.EqualTo("base"));
56+
supSet(sub, "base");
57+
Assert.That(supGet(sub), Is.EqualTo("base"));
58+
}
59+
60+
[Test]
61+
public void Can_get_field_accessor_from_sub_and_super_types()
62+
{
63+
var sub = new SubAccessor();
64+
var subGet = StaticAccessors.GetValueGetter<SubAccessor>(typeof(SubAccessor).GetField("SubField"));
65+
var subSet = StaticAccessors.GetValueSetter<SubAccessor>(typeof(SubAccessor).GetField("SubField"));
66+
67+
subSet(sub, "sub");
68+
Assert.That(subGet(sub), Is.EqualTo("sub"));
69+
70+
var sup = new AccessorBase();
71+
var supGet = StaticAccessors.GetValueGetter<AccessorBase>(typeof(AccessorBase).GetField("BaseField"));
72+
var supSet = StaticAccessors.GetValueSetter<AccessorBase>(typeof(AccessorBase).GetField("BaseField"));
73+
74+
supSet(sup, "base");
75+
Assert.That(supGet(sup), Is.EqualTo("base"));
76+
supSet(sub, "base");
77+
Assert.That(supGet(sub), Is.EqualTo("base"));
78+
}
3179
}
80+
81+
3282
}

0 commit comments

Comments
 (0)