File: LambdaMetaAccessor.cs

package info (click to toggle)
mono 4.6.2.7+dfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 778,148 kB
  • ctags: 914,052
  • sloc: cs: 5,779,509; xml: 2,773,713; ansic: 432,645; sh: 14,749; makefile: 12,361; perl: 2,488; python: 1,434; cpp: 849; asm: 531; sql: 95; sed: 16; php: 1
file content (118 lines) | stat: -rwxr-xr-x 3,579 bytes parent folder | download | duplicates (2)
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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
´╗┐using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Reflection;
using System.Data.Linq.Mapping;
using System.Reflection.Emit;

namespace DbLinq.Data.Linq.Mapping
{
	static class LambdaMetaAccessor
	{
		//This will go away with C# 4.0 ActionExpression
		static Delegate MakeSetter(MemberInfo member, Type memberType, Type declaringType)
		{
			Type delegateType = typeof(Action<,>).MakeGenericType(declaringType, memberType);

			switch (member.MemberType)
			{
				case MemberTypes.Property: {
                    MethodInfo method = ((PropertyInfo)member).GetSetMethod();
                    if (method != null)
                        return Delegate.CreateDelegate(delegateType, method);
                    var ca = member.GetCustomAttributes(typeof(ColumnAttribute), true)[0] as ColumnAttribute;
                    member = declaringType.GetField(ca.Storage,
                        BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static);
                    goto case MemberTypes.Field;
                }
				case MemberTypes.Field:
					{
						DynamicMethod m = new DynamicMethod("setter", 
                            typeof(void), 
                            new Type[] { declaringType, memberType },
                            true);
						ILGenerator cg = m.GetILGenerator();
					
						// arg0.<field> = arg1
						cg.Emit(OpCodes.Ldarg_0);
						cg.Emit(OpCodes.Ldarg_1);
						cg.Emit(OpCodes.Stfld, (FieldInfo)member);
						cg.Emit(OpCodes.Ret);
					
						return m.CreateDelegate(delegateType);
					}
				case MemberTypes.Method:
					 return Delegate.CreateDelegate(delegateType, (MethodInfo)member);
				default:
					throw new InvalidOperationException();
			}
		}

		public static MetaAccessor Create(MemberInfo member, Type declaringType)
		{
			Type memberType;
			switch (member.MemberType)
			{
				case MemberTypes.Property:
					memberType = ((PropertyInfo)member).PropertyType;
					break;
				case MemberTypes.Field:
					memberType = ((FieldInfo)member).FieldType;
					break;
				case MemberTypes.Method:
					memberType = ((MethodInfo)member).ReturnType;
					break;
				default:
					throw new InvalidOperationException();
			}
			Type accessorType = typeof(LambdaMetaAccessor<,>).MakeGenericType(declaringType, memberType);
			
			ParameterExpression p = Expression.Parameter(declaringType, "e");
			return (MetaAccessor)Activator.CreateInstance(accessorType, new object[]{ 
				Expression.Lambda(Expression.MakeMemberAccess(p, member), p).Compile(),
				MakeSetter(member, memberType, declaringType) }
			);
		}
	}

	class LambdaMetaAccessor<TEntity, TMember> : MetaAccessor<TEntity, TMember>
	{
		Func<TEntity, TMember> _Accessor;
		Action<TEntity, TMember> _Setter;

		public LambdaMetaAccessor(Func<TEntity, TMember> accessor, Action<TEntity, TMember> setter)
		{
			_Accessor = accessor;
			_Setter = setter;
		}

		//
		// Summary:
		//     Specifies the strongly typed value.
		//
		// Parameters:
		//   instance:
		//     The instance from which to get the value.
		public override TMember GetValue(TEntity instance)
		{
			return _Accessor(instance);
		}

		//
		// Summary:
		//     Specifies an instance on which to set the strongly typed value.
		//
		// Parameters:
		//   instance:
		//     The instance into which to set the value.
		//
		//   value:
		//     The strongly typed value to set.
		public override void SetValue(ref TEntity instance, TMember value)
		{
			_Setter(instance, value);
		}
	}
}