No hay una buena manera ... puedes hackear tu entrada, sin embargo. Por ejemplo imagine que tiene un objeto User
que sabe que está codificado por medio Id
:
var user = // get some user
var dataContext = // your DB context
const BindingFlags AllInstance = BindingFlags.Instance | BindingFlags.NonPublic
| BindingFlags.Public;
object commonDataServices = typeof(DataContext)
.GetField("services", AllInstance)
.GetValue(dataContext);
object identifier = commonDataServices.GetType()
.GetProperty("IdentityManager", AllInstance)
.GetValue(commonDataServices, null);
MethodInfo find = identifier.GetType().GetMethod("Find", AllInstance);
var metaType = dataContext.Mapping.GetMetaType(typeof(User));
object[] keys = new object[] { user.Id };
var user2 = (User)find.Invoke(identifier, new object[] { metaType, keys });
bool pass = ReferenceEquals(user, user2);
Pretty-tanto cada acceso es no pública; Esperaría que esto suck a nivel de rendimiento a menos que use DynamicMethod
para falsificar el acceso de otro tipo.
Y como una versión DynamicMethod
:
(sí, soy difícil de codificación a una clave int
... que podría hacer cualquier valor individual mediante la sustitución de la int
con object
, y simplemente dejar caer el OpCodes.Box, typeof(int)
- o puede que sea un argumento params object[]
y pasarlo directamente)
static readonly Func<DataContext, Type, int, object> identityLookup = BuildIdentityLookup();
static Func<DataContext, Type, int, object> BuildIdentityLookup()
{
var quickFind = new DynamicMethod("QuickFind", typeof(object), new Type[] { typeof(DataContext), typeof(Type), typeof(int) }, typeof(DataContext), true);
var il = quickFind.GetILGenerator();
const BindingFlags AllInstance = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public;
il.Emit(OpCodes.Ldarg_0); // DB
var services = typeof(DataContext).GetField("services", AllInstance);
il.Emit(OpCodes.Ldfld, services); // services
var identifier = services.FieldType.GetProperty("IdentityManager", AllInstance);
il.EmitCall(OpCodes.Callvirt, identifier.GetGetMethod(true), null); // identifier
il.Emit(OpCodes.Ldarg_0); // identifier DB
var mapping = typeof(DataContext).GetProperty("Mapping");
il.EmitCall(OpCodes.Callvirt, mapping.GetGetMethod(), null); // identifier mapping
il.Emit(OpCodes.Ldarg_1); // identifier mapping type
il.EmitCall(OpCodes.Callvirt, mapping.PropertyType.GetMethod("GetMetaType"), null); // identifier metatype
il.Emit(OpCodes.Ldc_I4_1); // identifier metatype 1
il.Emit(OpCodes.Newarr, typeof(object)); // identifier metatype object[]
il.Emit(OpCodes.Dup); // identifier metatype object[] object[]
il.Emit(OpCodes.Ldc_I4_0); // identifier metatype object[] object[] 0
il.Emit(OpCodes.Ldarg_2); // identifier metatype object[] object[] 0 id
il.Emit(OpCodes.Box, typeof(int)); // identifier metatype object[] object[] 0 boxed-id
il.Emit(OpCodes.Stelem_Ref); // identifier metatype object[]
il.EmitCall(OpCodes.Callvirt, identifier.PropertyType.GetMethod("Find", AllInstance), null); // object
il.Emit(OpCodes.Ret);
return (Func<DataContext, Type, int, object>)quickFind.CreateDelegate(typeof(Func<DataContext, Type, int, object>));
}
... oh el horror :) –