En fait, j’aurais dû demander: comment puis-je faire cela et restr conforme à CLS? Parce que la seule façon pour moi de procéder est la suivante, mais utiliser __makeref
, FieldInfo.SetValueDirect
ou simplement System.TypedReference
en général invalide la conformité CLS.
// code illustrating the issue: TestFields fields = new TestFields { MaxValue = 1234 }; // test struct with one field FieldInfo info = fields.GetType().GetField("MaxValue"); // get the FieldInfo // actual magic, no boxing, not CLS compliant: TypedReference reference = __makeref(fields); info.SetValueDirect(reference, 4096);
La contrepartie conforme de SetValueDirect
est SetValue
, mais elle prend un object comme cible. Par conséquent, ma structure est encadrée, ce qui me permet de définir une valeur sur une copie et non la variable d’origine.
Un équivalent générique de SetValue
n’existe pas, à ma connaissance. Existe-t-il un autre moyen de définir le champ d’une (référence à a) struct par reflection?
Créer un wrapper compatible avec Cls sur SetValueDirect:
var item = new MyStruct { X = 10 }; item.GetType().GetField("X").SetValueForValueType(ref item, 4); [CLSCompliant(true)] static class Hlp { public static void SetValueForValueType(this FieldInfo field, ref T item, object value) where T : struct { field.SetValueDirect(__makeref(item), value); } }
Pour les propriétés, si vous avez les types struct et property, vous pouvez créer un délégué à partir du configurateur de propriétés. Comme vous l’avez fait remarquer, les champs n’ont pas de parameters, mais vous pouvez en créer un qui se comporte exactement de la même manière:
delegate void RefAction(ref T1 arg1, T2 arg2); struct TestFields { public int MaxValue; public int MaxValueProperty { get { return MaxValue; } set { MaxValue = value; } } }; static class Program { static void Main(ssortingng[] args) { var propertyInfo = typeof(TestFields).GetProperty("MaxValueProperty"); var propertySetter = (RefAction)Delegate.CreateDelegate(typeof(RefAction), propertyInfo.GetSetMethod()); var fieldInfo = typeof(TestFields).GetField("MaxValue"); var dynamicMethod = new DynamicMethod(Ssortingng.Empty, typeof(void), new Type[] { fieldInfo.ReflectedType.MakeByRefType(), fieldInfo.FieldType }, true); var ilGenerator = dynamicMethod.GetILGenerator(); ilGenerator.Emit(OpCodes.Ldarg_0); ilGenerator.Emit(OpCodes.Ldarg_1); ilGenerator.Emit(OpCodes.Stfld, fieldInfo); ilGenerator.Emit(OpCodes.Ret); var fieldSetter = (RefAction)dynamicMethod.CreateDelegate(typeof(RefAction)); var fields = new TestFields { MaxValue = 1234 }; propertySetter(ref fields, 5678); fieldSetter(ref fields, 90); Console.WriteLine(fields.MaxValue); } }
Vous ne savez pas si cela correspond à vos contraintes, mais en déclarant l’instance de struct comme étant ValueType
, SetValue
fonctionnera comme prévu.
ValueType fields = new TestFields { MaxValue = 1234 }; // test struct with one field FieldInfo info = typeof(TestFields).GetField("MaxValue"); // get the FieldInfo info.SetValue(fields, 4096); Console.WriteLine(((TestFields)fields).MaxValue); // 4096
Voir cette réponse pour plus d’informations.