-
Notifications
You must be signed in to change notification settings - Fork 0
/
RefExtensions.cs
56 lines (50 loc) · 1.96 KB
/
RefExtensions.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
namespace AnyReference
{
using System;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
public static class Ref
{
public static Ref<T> Of<T>(Expression<Func<T>> expr)
{
var get = expr.Compile();
var param = new[] { Expression.Parameter(typeof(T)) };
var op = CreateSetOperation((dynamic) expr.Body, param[0]);
var act = Expression.Lambda<Action<T>>(op, param);
var set = act.Compile();
return new Ref<T>(get, set);
}
internal static Expression CreateSetOperation(Expression expr, Expression param)
{
throw new NotSupportedException("This kind of expression is not supported for assignment.");
}
internal static Expression CreateSetOperation(BinaryExpression expr, Expression param)
{
var access = Expression.ArrayAccess(expr.Left, expr.Right);
return Expression.Assign(access, param );
}
internal static Expression CreateSetOperation(MemberExpression expr, Expression param)
{
var propertyInfo = expr.Member as PropertyInfo;
if (propertyInfo != null && !propertyInfo.CanWrite)
{
return Expression.Throw(Expression.New(typeof(InvalidOperationException)));
}
return Expression.Assign(expr, param);
}
internal static Expression CreateSetOperation(MethodCallExpression expr, Expression param)
{
var setterName = expr.Method.Name.Replace("get_", "set_");
var setter = expr.Method.DeclaringType?.GetMethod(setterName);
if (setter == null)
{
return Expression.Throw(Expression.New(typeof(InvalidOperationException)));
}
else
{
return Expression.Call(expr.Object, setter, expr.Arguments.Concat(new[] { param }));
}
}
}
}