簡體   English   中英

我可以通過反射在沒有裝箱的情況下在結構上設置值嗎?

[英]Can I set a value on a struct through reflection without boxing?

實際上,我應該問:我怎么能這樣做保持CLS合規? 因為我能想到這樣做的唯一方法如下,但使用__makerefFieldInfo.SetValueDirect或只是System.TypedReference通常會使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);

SetValueDirect的兼容對應物是SetValue ,但是它將對象作為目標,因此我的結構將被裝箱,使我在副本上設置值,而不是原始變量。

據我所知, SetValue的通用對應物不存在。 有沒有其他方法通過反射設置(引用)結構的字段?

對於屬性,如果您具有struct和property類型,則可以從屬性setter創建委托。 正如您所指出的,字段沒有setter,但您可以創建一個行為完全相同的字段:

delegate void RefAction<T1, T2>(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(string[] args)
    {
        var propertyInfo = typeof(TestFields).GetProperty("MaxValueProperty");
        var propertySetter = (RefAction<TestFields, int>)Delegate.CreateDelegate(typeof(RefAction<TestFields, int>), propertyInfo.GetSetMethod());

        var fieldInfo = typeof(TestFields).GetField("MaxValue");

        var dynamicMethod = new DynamicMethod(String.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<TestFields, int>)dynamicMethod.CreateDelegate(typeof(RefAction<TestFields, int>));

        var fields = new TestFields { MaxValue = 1234 };
        propertySetter(ref fields, 5678);
        fieldSetter(ref fields, 90);
        Console.WriteLine(fields.MaxValue);
    }
}

在SetValueDirect上創建符合cls的包裝器:

  var item = new MyStruct { X = 10 };

  item.GetType().GetField("X").SetValueForValueType(ref item, 4);


[CLSCompliant(true)]
static class Hlp
{
  public static void SetValueForValueType<T>(this FieldInfo field, ref T item, object value) where T : struct
  {
    field.SetValueDirect(__makeref(item), value);
  }
}

不確定這是否適合您的約束,但通過將結構實例聲明為ValueTypeSetValue將按預期工作。

    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

有關更多信息,請參閱此答案

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM