Disons que j'ai le code suivant qui met à jour un champ d'un struct code> à l'aide de la réflexion. Étant donné que l'instance de structure est copiée dans la méthode code> dynamicUpdate code>, Il doit être encadré à un objet avant d'être passé .
static void Main()
{
var action = CreateSetIdDelegate(typeof(Person));
object person = RuntimeHelpers.GetObjectValue(new Person());
action(person, 10);
Console.WriteLine(((Person)person).id); // print 10
}
private static Action<object, object> CreateSetIdDelegate(Type t)
{
// build dynamic method and return delegate
}
6 Réponses :
Vous voudrez peut-être consulter des méthodes dynamiques (la réflexion ne doit pas nécessairement être lente!) ... P>
Gerhard a un bon message à ce sujet: http://jachman.wordpress.com/2006/08/22/2000-faster-utilisateur-dynamic-method-calls/ P>
C'est ce que je fais (et demandez dans cette question); Je souhaite remplacer la réflexion en utilisant la méthode dynamique et la question demande si je peux partager la même API de création de déléguée pour les structures et les classes.
modifier à nouveau strong>: cette tâche structure maintenant. Il y a une façon magnifique de le faire en C # 4, mais vous devrez écrire votre propre Ceci fonctionne en C # 4 (testé): P> ilGenerator code> émetteur code pour quoi que ce soit avant cela. Ils ont ajouté un
expressiontype.Assign code> sur la tramette .NET 4. P>
public struct SomeType
{
public int member;
}
[TestMethod]
public void TestIL()
{
FieldInfo field = typeof(SomeType).GetField("member");
var setter = BuildSetter(field);
SomeType instance = new SomeType();
int value = 12;
setter(ref instance, value);
Assert.AreEqual(value, instance.member);
}
Nice utilisation de la déclaration de C # 4 et. +1. Mais l'utilisation de ref i> est S / T, je veux éviter (voir la 2ème balle dans ma question) car je ne veux pas créer de délégués séparés pour Struct Setter & Class Setter.
Pour une structure, vous devez le transmettre par REF à apporter des modifications à l'original. Puisque vous ne pouvez pas ajouter ref code> ou
out code> à l'action
J'ai rencontré un problème similaire et cela m'a pris la majeure partie d'un week-end, mais je l'ai finalement compris après beaucoup de recherches, de lecture et de désassemblage de projets de test C #. Et cette version ne nécessite que .NET 2, pas 4.
public delegate void SetterDelegate(ref object target, object value); private static Type[] ParamTypes = new Type[] { typeof(object).MakeByRefType(), typeof(object) }; private static SetterDelegate CreateSetMethod(MemberInfo memberInfo) { Type ParamType; if (memberInfo is PropertyInfo) ParamType = ((PropertyInfo)memberInfo).PropertyType; else if (memberInfo is FieldInfo) ParamType = ((FieldInfo)memberInfo).FieldType; else throw new Exception("Can only create set methods for properties and fields."); DynamicMethod setter = new DynamicMethod( "", typeof(void), ParamTypes, memberInfo.ReflectedType.Module, true); ILGenerator generator = setter.GetILGenerator(); generator.Emit(OpCodes.Ldarg_0); generator.Emit(OpCodes.Ldind_Ref); if (memberInfo.DeclaringType.IsValueType) { #if UNSAFE_IL generator.Emit(OpCodes.Unbox, memberInfo.DeclaringType); #else generator.DeclareLocal(memberInfo.DeclaringType.MakeByRefType()); generator.Emit(OpCodes.Unbox, memberInfo.DeclaringType); generator.Emit(OpCodes.Stloc_0); generator.Emit(OpCodes.Ldloc_0); #endif // UNSAFE_IL } generator.Emit(OpCodes.Ldarg_1); if (ParamType.IsValueType) generator.Emit(OpCodes.Unbox_Any, ParamType); if (memberInfo is PropertyInfo) generator.Emit(OpCodes.Callvirt, ((PropertyInfo)memberInfo).GetSetMethod()); else if (memberInfo is FieldInfo) generator.Emit(OpCodes.Stfld, (FieldInfo)memberInfo); if (memberInfo.DeclaringType.IsValueType) { #if !UNSAFE_IL generator.Emit(OpCodes.Ldarg_0); generator.Emit(OpCodes.Ldloc_0); generator.Emit(OpCodes.Ldobj, memberInfo.DeclaringType); generator.Emit(OpCodes.Box, memberInfo.DeclaringType); generator.Emit(OpCodes.Stind_Ref); #endif // UNSAFE_IL } generator.Emit(OpCodes.Ret); return (SetterDelegate)setter.CreateDelegate(typeof(SetterDelegate)); }
Bonne réponse. Pour mon problème particulier (c'est-à-dire à mettre en œuvre ma bibliothèque fasterflect.codeplex.com ), je ne voulais pas faire utilisation de 'ref' du tout. Au lieu de cela, j'ai besoin que le code d'appel puisse passer dans une emballeuse de structure qui est un type de valeur.
Cela ne me laissera pas commenter sur la réponse de Hugh ci-dessous, alors je vais répondre ici. Fondamentalement pour définir un champ sur une structure, vous devez encadrer la structure d'abord, comme ceci: objet x = nouveau muntructeur (); Ensuite, vous passez l'objet en boîte en réf. Si vous savez déjà quel type vous avez affaire à l'avance, vous n'avez pas besoin de ce code du tout. Et si vous ne savez pas quel type il s'agit, cela signifie qu'il est probablement dans une référence d'objet déjà. J'espère que cela a du sens.
@Brycewagner peut-il être fait avec le paramètre connu au moment de l'exécution? Changera typeof (objet) .MakeByRefType (), typeof (objet) code> à
typeof (connu de type) .MakeBeReftype (), typeof (connectéfieldtype) code> suffit? Je ne connais tout simplement pas la partie émettrice et je ne peux toujours pas utiliser le .NET 4.0.
@Agentfire Si vous faites cela, votre type de délégué devra être SetterDelegate (Ref connu de l'OBJ, valeur connueFieldType) code>. Et si vous en savez assez pour créer votre délégué avec ces types, je ne sais pas que vous n'avez pas besoin de dynamicmethod pour faire votre délégué pour vous.
@Brycewagner VOIR, j'ai toujours des problèmes de construction d'un arbre d'expression (.NET 3.5) qui définirait des champs de structures. Votre code est le seul code sur Internet qui fonctionne parfaitement de cette manière, mais j'aimerais savoir s'il est possible de supprimer la boxe / une boîte de commande de ce code, car je suis en mesure de créer plusieurs variantes de celui-ci (avec différents types). , mais j'ai toujours besoin de le faire de manière dynamique.
Vous pouvez le modifier assez facilement pour travailler avec les structures. C'est actuellement basé sur le dictionnaire mais votre situation est plus facile. P>
http://www.damonpayne.com/2009/09/07 /TwowaybindingtonamevaluePairs.aspx p>
Après quelques expériences:
public delegate void ClassFieldSetter<in T, in TValue>(T target, TValue value) where T : class; public delegate void StructFieldSetter<T, in TValue>(ref T target, TValue value) where T : struct; public static class FieldSetterCreator { public static ClassFieldSetter<T, TValue> CreateClassFieldSetter<T, TValue>(FieldInfo field) where T : class { return CreateSetter<T, TValue, ClassFieldSetter<T, TValue>>(field); } public static StructFieldSetter<T, TValue> CreateStructFieldSetter<T, TValue>(FieldInfo field) where T : struct { return CreateSetter<T, TValue, StructFieldSetter<T, TValue>>(field); } private static TDelegate CreateSetter<T, TValue, TDelegate>(FieldInfo field) { return (TDelegate)(object)CreateSetter(field, typeof(T), typeof(TValue), typeof(TDelegate)); } private static Delegate CreateSetter(FieldInfo field, Type instanceType, Type valueType, Type delegateType) { if (!field.DeclaringType.IsAssignableFrom(instanceType)) throw new ArgumentException("The field is declared it different type"); if (!field.FieldType.IsAssignableFrom(valueType)) throw new ArgumentException("The field type is not assignable from the value"); var paramType = instanceType.IsValueType ? instanceType.MakeByRefType() : instanceType; var setter = new DynamicMethod("", typeof(void), new[] { paramType, valueType }, field.DeclaringType.Module, true); var generator = setter.GetILGenerator(); generator.Emit(OpCodes.Ldarg_0); generator.Emit(OpCodes.Ldarg_1); generator.Emit(OpCodes.Stfld, field); generator.Emit(OpCodes.Ret); return setter.CreateDelegate(delegateType); } }
Ce code fonctionne pour les structures sans utiliser ref: voici mon code de test: p>
Utilise une structure mutable vraiment i> votre meilleure option ici? C'est presque toujours une douleur pour de nombreuses raisons, et il semble que vous couriez dans certains d'entre eux ...
Avez-vous envisagé de compiler un arbre d'expression au lieu d'émettre des IL? Cela devrait être beaucoup plus facile.
@Jon: En fait, je construis je construis une API de réflexion rapide ( Fasterflect.Codeplex.com ) alors prise en charge de la structure Les opérations de réflexion seraient souhaitables par certaines personnes.
@Mehrdad: Je n'ai pas essayé ça. Je ne suis pas sûr de la performance entre la compilation de l'ET à un délégué et de convertir une méthode dynamique à un délégué - je suppose que ce dernier est meilleur mais n'a pas essayé en fait.