Change Encoding key to workaround collision with Encoding parameter names used by...
[mono.git] / mcs / class / referencesource / System.Data.Linq / Mapping / Accessors.cs
1 using System;
2 using System.Collections;
3 using System.Collections.Generic;
4 using System.Linq.Expressions;
5 using System.Reflection;
6 using System.Reflection.Emit;
7 using System.Security.Permissions;
8 using System.Security;
9 using System.Runtime.CompilerServices;
10
11 namespace System.Data.Linq.Mapping {
12     using System.Data.Linq.Provider;
13     using System.Diagnostics.CodeAnalysis;
14
15     internal delegate V DGet<T, V>(T t);
16     internal delegate void DSet<T, V>(T t, V v);
17     internal delegate void DRSet<T, V>(ref T t, V v);
18
19     internal static class FieldAccessor {
20
21         [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
22         internal static MetaAccessor Create(Type objectType, FieldInfo fi) {
23             if (!fi.ReflectedType.IsAssignableFrom(objectType))
24                 throw Error.InvalidFieldInfo(objectType, fi.FieldType, fi);
25             Delegate dget = null;
26             Delegate drset = null;
27
28             if (!objectType.IsGenericType) {
29                 DynamicMethod mget = new DynamicMethod(
30                     "xget_" + fi.Name,
31                     fi.FieldType,
32                     new Type[] { objectType },
33                     true
34                     );
35                 ILGenerator gen = mget.GetILGenerator();
36                 gen.Emit(OpCodes.Ldarg_0);
37                 gen.Emit(OpCodes.Ldfld, fi);
38                 gen.Emit(OpCodes.Ret);
39                 dget = mget.CreateDelegate(typeof(DGet<,>).MakeGenericType(objectType, fi.FieldType));
40
41                 DynamicMethod mset = new DynamicMethod(
42                     "xset_" + fi.Name,
43                     typeof(void),
44                     new Type[] { objectType.MakeByRefType(), fi.FieldType },
45                     true
46                     );
47                 gen = mset.GetILGenerator();
48                 gen.Emit(OpCodes.Ldarg_0);
49                 if (!objectType.IsValueType) {
50                     gen.Emit(OpCodes.Ldind_Ref);
51                 }
52                 gen.Emit(OpCodes.Ldarg_1);
53                 gen.Emit(OpCodes.Stfld, fi);
54                 gen.Emit(OpCodes.Ret);
55                 drset = mset.CreateDelegate(typeof(DRSet<,>).MakeGenericType(objectType, fi.FieldType));
56             }
57             return (MetaAccessor)Activator.CreateInstance(
58                 typeof(Accessor<,>).MakeGenericType(objectType, fi.FieldType),
59                 BindingFlags.Instance | BindingFlags.NonPublic, null,
60                 new object[] { fi, dget, drset }, null
61                 );
62         }
63
64         class Accessor<T, V> : MetaAccessor<T, V> { 
65             DGet<T, V> dget;
66             DRSet<T, V> drset;
67             FieldInfo fi;
68
69             internal Accessor(FieldInfo fi, DGet<T, V> dget, DRSet<T, V> drset) {
70                 this.fi = fi;
71                 this.dget = dget;
72                 this.drset = drset;
73             }
74             public override V GetValue(T instance) {
75                 if (this.dget != null)
76                     return this.dget(instance);
77                 return (V)fi.GetValue(instance);
78             }
79             public override void SetValue(ref T instance, V value) {
80                 if (this.drset != null)
81                     this.drset(ref instance, value);
82                 else
83                     this.fi.SetValue(instance, value);
84             }
85         }
86     }
87
88     internal static class PropertyAccessor {
89
90         internal static MetaAccessor Create(Type objectType, PropertyInfo pi, MetaAccessor storageAccessor) {
91             Delegate dset = null;
92             Delegate drset = null;
93             Type dgetType = typeof(DGet<,>).MakeGenericType(objectType, pi.PropertyType);
94             MethodInfo getMethod = pi.GetGetMethod(true);
95
96             Delegate dget = Delegate.CreateDelegate(dgetType, getMethod, true);
97             if (dget == null) {
98                 throw Error.CouldNotCreateAccessorToProperty(objectType, pi.PropertyType, pi);
99             }
100
101             if (pi.CanWrite) {
102                 if (!objectType.IsValueType) {
103                     dset = Delegate.CreateDelegate(typeof(DSet<,>).MakeGenericType(objectType, pi.PropertyType), pi.GetSetMethod(true), true);
104                 }
105                 else {
106                     DynamicMethod mset = new DynamicMethod(
107                         "xset_" + pi.Name,
108                         typeof(void),
109                         new Type[] { objectType.MakeByRefType(), pi.PropertyType },
110                         true
111                         );
112                     ILGenerator gen = mset.GetILGenerator();
113                     gen.Emit(OpCodes.Ldarg_0);
114                     if (!objectType.IsValueType) {
115                         gen.Emit(OpCodes.Ldind_Ref);
116                     }
117                     gen.Emit(OpCodes.Ldarg_1);
118                     gen.Emit(OpCodes.Call, pi.GetSetMethod(true));
119                     gen.Emit(OpCodes.Ret);
120                     drset = mset.CreateDelegate(typeof(DRSet<,>).MakeGenericType(objectType, pi.PropertyType));
121                 }
122             }
123
124             Type saType = (storageAccessor != null) ? storageAccessor.Type : pi.PropertyType;
125             return (MetaAccessor)Activator.CreateInstance(
126                 typeof(Accessor<,,>).MakeGenericType(objectType, pi.PropertyType, saType),
127                 BindingFlags.Instance|BindingFlags.NonPublic, null, 
128                 new object[] {pi, dget, dset, drset, storageAccessor}, null        
129                 );
130             }
131
132
133         class Accessor<T,V, V2> : MetaAccessor<T,V> where V2 : V {
134             PropertyInfo pi;
135             DGet<T, V> dget;
136             DSet<T, V> dset;
137             DRSet<T, V> drset;
138             MetaAccessor<T, V2> storage;
139
140             internal Accessor(PropertyInfo pi, DGet<T, V> dget, DSet<T, V> dset, DRSet<T, V> drset, MetaAccessor<T,V2> storage) {
141                 this.pi = pi;
142                 this.dget = dget;
143                 this.dset = dset;
144                 this.drset = drset;
145                 this.storage = storage;
146             }
147             public override V GetValue(T instance) {
148                 return this.dget(instance);
149             }
150             public override void SetValue(ref T instance, V value) {
151                 if (this.dset != null) {
152                     this.dset(instance, value);
153                 }
154                 else if (this.drset != null) {
155                     this.drset(ref instance, value);
156                 }
157                 else if (this.storage != null) {
158                     this.storage.SetValue(ref instance, (V2)value);
159                 }
160                 else {
161                     throw Error.UnableToAssignValueToReadonlyProperty(this.pi);
162                 }
163             }
164         }
165     }
166     
167     // deferred type accessors 
168     internal class LinkValueAccessor<T, V> : MetaAccessor<T, V> {
169         MetaAccessor<T, Link<V>> acc;
170         internal LinkValueAccessor(MetaAccessor<T, Link<V>> acc) {
171             this.acc = acc;
172         }
173         public override bool HasValue(object instance) {
174             Link<V> link = this.acc.GetValue((T)instance);
175             return link.HasValue;
176         }
177         public override bool HasAssignedValue(object instance) {
178             Link<V> link = this.acc.GetValue((T)instance);
179             return link.HasAssignedValue;
180         }
181         public override bool HasLoadedValue(object instance) {
182             Link<V> link = this.acc.GetValue((T)instance);
183             return link.HasLoadedValue;
184         }
185         public override V GetValue(T instance) {
186             Link<V> link = this.acc.GetValue(instance);
187             return link.Value;
188         }
189         public override void SetValue(ref T instance, V value) {
190             this.acc.SetValue(ref instance, new Link<V>(value));
191         }
192     }
193
194     internal class LinkDefValueAccessor<T, V> : MetaAccessor<T, V> {
195         MetaAccessor<T, Link<V>> acc;
196         internal LinkDefValueAccessor(MetaAccessor<T, Link<V>> acc) {
197             this.acc = acc;
198         }
199         public override V GetValue(T instance) {
200             Link<V> link = this.acc.GetValue(instance);
201             return link.UnderlyingValue;
202         }
203         public override void SetValue(ref T instance, V value) {
204             this.acc.SetValue(ref instance, new Link<V>(value));
205         }
206     }
207
208     internal class LinkDefSourceAccessor<T, V> : MetaAccessor<T, IEnumerable<V>> {
209         MetaAccessor<T, Link<V>> acc;
210         internal LinkDefSourceAccessor(MetaAccessor<T, Link<V>> acc) {
211             this.acc = acc;
212         }
213         public override IEnumerable<V> GetValue(T instance) {
214             Link<V> link = this.acc.GetValue(instance);
215             return (IEnumerable<V>)link.Source;
216         }
217         public override void SetValue(ref T instance, IEnumerable<V> value) {
218             Link<V> link = this.acc.GetValue(instance);
219             if (link.HasAssignedValue || link.HasLoadedValue) {
220                 throw Error.LinkAlreadyLoaded();
221             }
222             this.acc.SetValue(ref instance, new Link<V>(value));
223         }
224     }
225
226     internal class EntityRefValueAccessor<T, V> : MetaAccessor<T, V> where V : class {
227         MetaAccessor<T, EntityRef<V>> acc;
228         internal EntityRefValueAccessor(MetaAccessor<T, EntityRef<V>> acc) {
229             this.acc = acc;
230         }
231         public override V GetValue(T instance) {
232             EntityRef<V> er = this.acc.GetValue(instance);
233             return er.Entity;
234         }
235         public override void SetValue(ref T instance, V value) {
236             this.acc.SetValue(ref instance, new EntityRef<V>(value));
237         }
238         public override bool HasValue(object instance) {
239             EntityRef<V> er = this.acc.GetValue((T)instance);
240             return er.HasValue;
241         }
242         public override bool HasAssignedValue(object instance) {
243             EntityRef<V> er = this.acc.GetValue((T)instance);
244             return er.HasAssignedValue;
245         }
246         public override bool HasLoadedValue(object instance) {
247             EntityRef<V> er = this.acc.GetValue((T)instance);
248             return er.HasLoadedValue;
249         }
250     }
251
252     internal class EntityRefDefValueAccessor<T, V> : MetaAccessor<T, V> where V : class {
253         MetaAccessor<T, EntityRef<V>> acc;
254         internal EntityRefDefValueAccessor(MetaAccessor<T, EntityRef<V>> acc) {
255             this.acc = acc;
256         }
257         public override V GetValue(T instance) {
258             EntityRef<V> er = this.acc.GetValue(instance);
259             return er.UnderlyingValue;
260         }
261         public override void SetValue(ref T instance, V value) {
262             this.acc.SetValue(ref instance, new EntityRef<V>(value));
263         }
264     }
265
266     internal class EntityRefDefSourceAccessor<T, V> : MetaAccessor<T, IEnumerable<V>> where V : class {
267         MetaAccessor<T, EntityRef<V>> acc;
268         internal EntityRefDefSourceAccessor(MetaAccessor<T, EntityRef<V>> acc) {
269             this.acc = acc;
270         }
271         public override IEnumerable<V> GetValue(T instance) {
272             EntityRef<V> er = this.acc.GetValue(instance);
273             return (IEnumerable<V>)er.Source;
274         }
275         public override void SetValue(ref T instance, IEnumerable<V> value) {
276             EntityRef<V> er = this.acc.GetValue(instance);
277             if (er.HasAssignedValue || er.HasLoadedValue) {
278                 throw Error.EntityRefAlreadyLoaded();
279             }
280             this.acc.SetValue(ref instance, new EntityRef<V>(value));
281         }
282     }
283
284     internal class EntitySetValueAccessor<T, V> : MetaAccessor<T, EntitySet<V>> where V : class {
285         MetaAccessor<T, EntitySet<V>> acc;
286         internal EntitySetValueAccessor(MetaAccessor<T, EntitySet<V>> acc) {
287             this.acc = acc;
288         }
289         public override EntitySet<V> GetValue(T instance) {
290             return this.acc.GetValue(instance);
291         }
292         public override void SetValue(ref T instance, EntitySet<V> value) {
293             EntitySet<V> eset = this.acc.GetValue(instance);
294             if (eset == null) {
295                 eset = new EntitySet<V>();
296                 this.acc.SetValue(ref instance, eset);
297             }
298             eset.Assign(value);
299         }
300         public override bool HasValue(object instance) {
301             EntitySet<V> es = this.acc.GetValue((T)instance);
302             return es != null && es.HasValues;
303         }
304         public override bool HasAssignedValue(object instance) {
305             EntitySet<V> es = this.acc.GetValue((T)instance);
306             return es != null && es.HasAssignedValues;
307         }
308         public override bool HasLoadedValue(object instance) {
309             EntitySet<V> es = this.acc.GetValue((T)instance);
310             return es != null && es.HasLoadedValues;
311         }
312     }
313
314     internal class EntitySetDefValueAccessor<T, V> : MetaAccessor<T, IEnumerable<V>> where V : class {
315         MetaAccessor<T, EntitySet<V>> acc;
316         internal EntitySetDefValueAccessor(MetaAccessor<T, EntitySet<V>> acc) {
317             this.acc = acc;
318         }
319         public override IEnumerable<V> GetValue(T instance) {
320             EntitySet<V> eset = this.acc.GetValue(instance);
321             return eset.GetUnderlyingValues();
322         }
323         public override void SetValue(ref T instance, IEnumerable<V> value) {
324             EntitySet<V> eset = this.acc.GetValue(instance);
325             if (eset == null) {
326                 eset = new EntitySet<V>();
327                 this.acc.SetValue(ref instance, eset);
328             }
329             eset.Assign(value);
330         }
331     }
332
333     internal class EntitySetDefSourceAccessor<T, V> : MetaAccessor<T, IEnumerable<V>> where V : class {
334         MetaAccessor<T, EntitySet<V>> acc;
335         internal EntitySetDefSourceAccessor(MetaAccessor<T, EntitySet<V>> acc) {
336             this.acc = acc;
337         }
338         public override IEnumerable<V> GetValue(T instance) {
339             EntitySet<V> eset = this.acc.GetValue(instance);
340             return (IEnumerable<V>)eset.Source;
341         }
342         public override void SetValue(ref T instance, IEnumerable<V> value) {
343             EntitySet<V> eset = this.acc.GetValue(instance);
344             if (eset == null) {
345                 eset = new EntitySet<V>();
346                 this.acc.SetValue(ref instance, eset);
347             }
348             eset.SetSource(value);
349         }
350     }
351 }