352 lines
14 KiB
C#
352 lines
14 KiB
C#
|
using System;
|
|||
|
using System.Collections;
|
|||
|
using System.Collections.Generic;
|
|||
|
using System.Linq.Expressions;
|
|||
|
using System.Reflection;
|
|||
|
using System.Reflection.Emit;
|
|||
|
using System.Security.Permissions;
|
|||
|
using System.Security;
|
|||
|
using System.Runtime.CompilerServices;
|
|||
|
|
|||
|
namespace System.Data.Linq.Mapping {
|
|||
|
using System.Data.Linq.Provider;
|
|||
|
using System.Diagnostics.CodeAnalysis;
|
|||
|
|
|||
|
internal delegate V DGet<T, V>(T t);
|
|||
|
internal delegate void DSet<T, V>(T t, V v);
|
|||
|
internal delegate void DRSet<T, V>(ref T t, V v);
|
|||
|
|
|||
|
internal static class FieldAccessor {
|
|||
|
|
|||
|
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
|
|||
|
internal static MetaAccessor Create(Type objectType, FieldInfo fi) {
|
|||
|
if (!fi.ReflectedType.IsAssignableFrom(objectType))
|
|||
|
throw Error.InvalidFieldInfo(objectType, fi.FieldType, fi);
|
|||
|
Delegate dget = null;
|
|||
|
Delegate drset = null;
|
|||
|
|
|||
|
if (!objectType.IsGenericType) {
|
|||
|
DynamicMethod mget = new DynamicMethod(
|
|||
|
"xget_" + fi.Name,
|
|||
|
fi.FieldType,
|
|||
|
new Type[] { objectType },
|
|||
|
true
|
|||
|
);
|
|||
|
ILGenerator gen = mget.GetILGenerator();
|
|||
|
gen.Emit(OpCodes.Ldarg_0);
|
|||
|
gen.Emit(OpCodes.Ldfld, fi);
|
|||
|
gen.Emit(OpCodes.Ret);
|
|||
|
dget = mget.CreateDelegate(typeof(DGet<,>).MakeGenericType(objectType, fi.FieldType));
|
|||
|
|
|||
|
DynamicMethod mset = new DynamicMethod(
|
|||
|
"xset_" + fi.Name,
|
|||
|
typeof(void),
|
|||
|
new Type[] { objectType.MakeByRefType(), fi.FieldType },
|
|||
|
true
|
|||
|
);
|
|||
|
gen = mset.GetILGenerator();
|
|||
|
gen.Emit(OpCodes.Ldarg_0);
|
|||
|
if (!objectType.IsValueType) {
|
|||
|
gen.Emit(OpCodes.Ldind_Ref);
|
|||
|
}
|
|||
|
gen.Emit(OpCodes.Ldarg_1);
|
|||
|
gen.Emit(OpCodes.Stfld, fi);
|
|||
|
gen.Emit(OpCodes.Ret);
|
|||
|
drset = mset.CreateDelegate(typeof(DRSet<,>).MakeGenericType(objectType, fi.FieldType));
|
|||
|
}
|
|||
|
return (MetaAccessor)Activator.CreateInstance(
|
|||
|
typeof(Accessor<,>).MakeGenericType(objectType, fi.FieldType),
|
|||
|
BindingFlags.Instance | BindingFlags.NonPublic, null,
|
|||
|
new object[] { fi, dget, drset }, null
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
class Accessor<T, V> : MetaAccessor<T, V> {
|
|||
|
DGet<T, V> dget;
|
|||
|
DRSet<T, V> drset;
|
|||
|
FieldInfo fi;
|
|||
|
|
|||
|
internal Accessor(FieldInfo fi, DGet<T, V> dget, DRSet<T, V> drset) {
|
|||
|
this.fi = fi;
|
|||
|
this.dget = dget;
|
|||
|
this.drset = drset;
|
|||
|
}
|
|||
|
public override V GetValue(T instance) {
|
|||
|
if (this.dget != null)
|
|||
|
return this.dget(instance);
|
|||
|
return (V)fi.GetValue(instance);
|
|||
|
}
|
|||
|
public override void SetValue(ref T instance, V value) {
|
|||
|
if (this.drset != null)
|
|||
|
this.drset(ref instance, value);
|
|||
|
else
|
|||
|
this.fi.SetValue(instance, value);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
internal static class PropertyAccessor {
|
|||
|
|
|||
|
internal static MetaAccessor Create(Type objectType, PropertyInfo pi, MetaAccessor storageAccessor) {
|
|||
|
Delegate dset = null;
|
|||
|
Delegate drset = null;
|
|||
|
Type dgetType = typeof(DGet<,>).MakeGenericType(objectType, pi.PropertyType);
|
|||
|
MethodInfo getMethod = pi.GetGetMethod(true);
|
|||
|
|
|||
|
Delegate dget = Delegate.CreateDelegate(dgetType, getMethod, true);
|
|||
|
if (dget == null) {
|
|||
|
throw Error.CouldNotCreateAccessorToProperty(objectType, pi.PropertyType, pi);
|
|||
|
}
|
|||
|
|
|||
|
if (pi.CanWrite) {
|
|||
|
if (!objectType.IsValueType) {
|
|||
|
dset = Delegate.CreateDelegate(typeof(DSet<,>).MakeGenericType(objectType, pi.PropertyType), pi.GetSetMethod(true), true);
|
|||
|
}
|
|||
|
else {
|
|||
|
DynamicMethod mset = new DynamicMethod(
|
|||
|
"xset_" + pi.Name,
|
|||
|
typeof(void),
|
|||
|
new Type[] { objectType.MakeByRefType(), pi.PropertyType },
|
|||
|
true
|
|||
|
);
|
|||
|
ILGenerator gen = mset.GetILGenerator();
|
|||
|
gen.Emit(OpCodes.Ldarg_0);
|
|||
|
if (!objectType.IsValueType) {
|
|||
|
gen.Emit(OpCodes.Ldind_Ref);
|
|||
|
}
|
|||
|
gen.Emit(OpCodes.Ldarg_1);
|
|||
|
gen.Emit(OpCodes.Call, pi.GetSetMethod(true));
|
|||
|
gen.Emit(OpCodes.Ret);
|
|||
|
drset = mset.CreateDelegate(typeof(DRSet<,>).MakeGenericType(objectType, pi.PropertyType));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
Type saType = (storageAccessor != null) ? storageAccessor.Type : pi.PropertyType;
|
|||
|
return (MetaAccessor)Activator.CreateInstance(
|
|||
|
typeof(Accessor<,,>).MakeGenericType(objectType, pi.PropertyType, saType),
|
|||
|
BindingFlags.Instance|BindingFlags.NonPublic, null,
|
|||
|
new object[] {pi, dget, dset, drset, storageAccessor}, null
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
class Accessor<T,V, V2> : MetaAccessor<T,V> where V2 : V {
|
|||
|
PropertyInfo pi;
|
|||
|
DGet<T, V> dget;
|
|||
|
DSet<T, V> dset;
|
|||
|
DRSet<T, V> drset;
|
|||
|
MetaAccessor<T, V2> storage;
|
|||
|
|
|||
|
internal Accessor(PropertyInfo pi, DGet<T, V> dget, DSet<T, V> dset, DRSet<T, V> drset, MetaAccessor<T,V2> storage) {
|
|||
|
this.pi = pi;
|
|||
|
this.dget = dget;
|
|||
|
this.dset = dset;
|
|||
|
this.drset = drset;
|
|||
|
this.storage = storage;
|
|||
|
}
|
|||
|
public override V GetValue(T instance) {
|
|||
|
return this.dget(instance);
|
|||
|
}
|
|||
|
public override void SetValue(ref T instance, V value) {
|
|||
|
if (this.dset != null) {
|
|||
|
this.dset(instance, value);
|
|||
|
}
|
|||
|
else if (this.drset != null) {
|
|||
|
this.drset(ref instance, value);
|
|||
|
}
|
|||
|
else if (this.storage != null) {
|
|||
|
this.storage.SetValue(ref instance, (V2)value);
|
|||
|
}
|
|||
|
else {
|
|||
|
throw Error.UnableToAssignValueToReadonlyProperty(this.pi);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// deferred type accessors
|
|||
|
internal class LinkValueAccessor<T, V> : MetaAccessor<T, V> {
|
|||
|
MetaAccessor<T, Link<V>> acc;
|
|||
|
internal LinkValueAccessor(MetaAccessor<T, Link<V>> acc) {
|
|||
|
this.acc = acc;
|
|||
|
}
|
|||
|
public override bool HasValue(object instance) {
|
|||
|
Link<V> link = this.acc.GetValue((T)instance);
|
|||
|
return link.HasValue;
|
|||
|
}
|
|||
|
public override bool HasAssignedValue(object instance) {
|
|||
|
Link<V> link = this.acc.GetValue((T)instance);
|
|||
|
return link.HasAssignedValue;
|
|||
|
}
|
|||
|
public override bool HasLoadedValue(object instance) {
|
|||
|
Link<V> link = this.acc.GetValue((T)instance);
|
|||
|
return link.HasLoadedValue;
|
|||
|
}
|
|||
|
public override V GetValue(T instance) {
|
|||
|
Link<V> link = this.acc.GetValue(instance);
|
|||
|
return link.Value;
|
|||
|
}
|
|||
|
public override void SetValue(ref T instance, V value) {
|
|||
|
this.acc.SetValue(ref instance, new Link<V>(value));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
internal class LinkDefValueAccessor<T, V> : MetaAccessor<T, V> {
|
|||
|
MetaAccessor<T, Link<V>> acc;
|
|||
|
internal LinkDefValueAccessor(MetaAccessor<T, Link<V>> acc) {
|
|||
|
this.acc = acc;
|
|||
|
}
|
|||
|
public override V GetValue(T instance) {
|
|||
|
Link<V> link = this.acc.GetValue(instance);
|
|||
|
return link.UnderlyingValue;
|
|||
|
}
|
|||
|
public override void SetValue(ref T instance, V value) {
|
|||
|
this.acc.SetValue(ref instance, new Link<V>(value));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
internal class LinkDefSourceAccessor<T, V> : MetaAccessor<T, IEnumerable<V>> {
|
|||
|
MetaAccessor<T, Link<V>> acc;
|
|||
|
internal LinkDefSourceAccessor(MetaAccessor<T, Link<V>> acc) {
|
|||
|
this.acc = acc;
|
|||
|
}
|
|||
|
public override IEnumerable<V> GetValue(T instance) {
|
|||
|
Link<V> link = this.acc.GetValue(instance);
|
|||
|
return (IEnumerable<V>)link.Source;
|
|||
|
}
|
|||
|
public override void SetValue(ref T instance, IEnumerable<V> value) {
|
|||
|
Link<V> link = this.acc.GetValue(instance);
|
|||
|
if (link.HasAssignedValue || link.HasLoadedValue) {
|
|||
|
throw Error.LinkAlreadyLoaded();
|
|||
|
}
|
|||
|
this.acc.SetValue(ref instance, new Link<V>(value));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
internal class EntityRefValueAccessor<T, V> : MetaAccessor<T, V> where V : class {
|
|||
|
MetaAccessor<T, EntityRef<V>> acc;
|
|||
|
internal EntityRefValueAccessor(MetaAccessor<T, EntityRef<V>> acc) {
|
|||
|
this.acc = acc;
|
|||
|
}
|
|||
|
public override V GetValue(T instance) {
|
|||
|
EntityRef<V> er = this.acc.GetValue(instance);
|
|||
|
return er.Entity;
|
|||
|
}
|
|||
|
public override void SetValue(ref T instance, V value) {
|
|||
|
this.acc.SetValue(ref instance, new EntityRef<V>(value));
|
|||
|
}
|
|||
|
public override bool HasValue(object instance) {
|
|||
|
EntityRef<V> er = this.acc.GetValue((T)instance);
|
|||
|
return er.HasValue;
|
|||
|
}
|
|||
|
public override bool HasAssignedValue(object instance) {
|
|||
|
EntityRef<V> er = this.acc.GetValue((T)instance);
|
|||
|
return er.HasAssignedValue;
|
|||
|
}
|
|||
|
public override bool HasLoadedValue(object instance) {
|
|||
|
EntityRef<V> er = this.acc.GetValue((T)instance);
|
|||
|
return er.HasLoadedValue;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
internal class EntityRefDefValueAccessor<T, V> : MetaAccessor<T, V> where V : class {
|
|||
|
MetaAccessor<T, EntityRef<V>> acc;
|
|||
|
internal EntityRefDefValueAccessor(MetaAccessor<T, EntityRef<V>> acc) {
|
|||
|
this.acc = acc;
|
|||
|
}
|
|||
|
public override V GetValue(T instance) {
|
|||
|
EntityRef<V> er = this.acc.GetValue(instance);
|
|||
|
return er.UnderlyingValue;
|
|||
|
}
|
|||
|
public override void SetValue(ref T instance, V value) {
|
|||
|
this.acc.SetValue(ref instance, new EntityRef<V>(value));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
internal class EntityRefDefSourceAccessor<T, V> : MetaAccessor<T, IEnumerable<V>> where V : class {
|
|||
|
MetaAccessor<T, EntityRef<V>> acc;
|
|||
|
internal EntityRefDefSourceAccessor(MetaAccessor<T, EntityRef<V>> acc) {
|
|||
|
this.acc = acc;
|
|||
|
}
|
|||
|
public override IEnumerable<V> GetValue(T instance) {
|
|||
|
EntityRef<V> er = this.acc.GetValue(instance);
|
|||
|
return (IEnumerable<V>)er.Source;
|
|||
|
}
|
|||
|
public override void SetValue(ref T instance, IEnumerable<V> value) {
|
|||
|
EntityRef<V> er = this.acc.GetValue(instance);
|
|||
|
if (er.HasAssignedValue || er.HasLoadedValue) {
|
|||
|
throw Error.EntityRefAlreadyLoaded();
|
|||
|
}
|
|||
|
this.acc.SetValue(ref instance, new EntityRef<V>(value));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
internal class EntitySetValueAccessor<T, V> : MetaAccessor<T, EntitySet<V>> where V : class {
|
|||
|
MetaAccessor<T, EntitySet<V>> acc;
|
|||
|
internal EntitySetValueAccessor(MetaAccessor<T, EntitySet<V>> acc) {
|
|||
|
this.acc = acc;
|
|||
|
}
|
|||
|
public override EntitySet<V> GetValue(T instance) {
|
|||
|
return this.acc.GetValue(instance);
|
|||
|
}
|
|||
|
public override void SetValue(ref T instance, EntitySet<V> value) {
|
|||
|
EntitySet<V> eset = this.acc.GetValue(instance);
|
|||
|
if (eset == null) {
|
|||
|
eset = new EntitySet<V>();
|
|||
|
this.acc.SetValue(ref instance, eset);
|
|||
|
}
|
|||
|
eset.Assign(value);
|
|||
|
}
|
|||
|
public override bool HasValue(object instance) {
|
|||
|
EntitySet<V> es = this.acc.GetValue((T)instance);
|
|||
|
return es != null && es.HasValues;
|
|||
|
}
|
|||
|
public override bool HasAssignedValue(object instance) {
|
|||
|
EntitySet<V> es = this.acc.GetValue((T)instance);
|
|||
|
return es != null && es.HasAssignedValues;
|
|||
|
}
|
|||
|
public override bool HasLoadedValue(object instance) {
|
|||
|
EntitySet<V> es = this.acc.GetValue((T)instance);
|
|||
|
return es != null && es.HasLoadedValues;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
internal class EntitySetDefValueAccessor<T, V> : MetaAccessor<T, IEnumerable<V>> where V : class {
|
|||
|
MetaAccessor<T, EntitySet<V>> acc;
|
|||
|
internal EntitySetDefValueAccessor(MetaAccessor<T, EntitySet<V>> acc) {
|
|||
|
this.acc = acc;
|
|||
|
}
|
|||
|
public override IEnumerable<V> GetValue(T instance) {
|
|||
|
EntitySet<V> eset = this.acc.GetValue(instance);
|
|||
|
return eset.GetUnderlyingValues();
|
|||
|
}
|
|||
|
public override void SetValue(ref T instance, IEnumerable<V> value) {
|
|||
|
EntitySet<V> eset = this.acc.GetValue(instance);
|
|||
|
if (eset == null) {
|
|||
|
eset = new EntitySet<V>();
|
|||
|
this.acc.SetValue(ref instance, eset);
|
|||
|
}
|
|||
|
eset.Assign(value);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
internal class EntitySetDefSourceAccessor<T, V> : MetaAccessor<T, IEnumerable<V>> where V : class {
|
|||
|
MetaAccessor<T, EntitySet<V>> acc;
|
|||
|
internal EntitySetDefSourceAccessor(MetaAccessor<T, EntitySet<V>> acc) {
|
|||
|
this.acc = acc;
|
|||
|
}
|
|||
|
public override IEnumerable<V> GetValue(T instance) {
|
|||
|
EntitySet<V> eset = this.acc.GetValue(instance);
|
|||
|
return (IEnumerable<V>)eset.Source;
|
|||
|
}
|
|||
|
public override void SetValue(ref T instance, IEnumerable<V> value) {
|
|||
|
EntitySet<V> eset = this.acc.GetValue(instance);
|
|||
|
if (eset == null) {
|
|||
|
eset = new EntitySet<V>();
|
|||
|
this.acc.SetValue(ref instance, eset);
|
|||
|
}
|
|||
|
eset.SetSource(value);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|