ReoCyan
ReoCyan

Reputation: 13

How do I fix this bug in Unity C# with getting a variable through reflection?

I have this code to find my variable:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using System.Reflection;
using System;

public class Shop : MonoBehaviour
{
    public MoneyScript MS;

    [SerializeField] GameObject ChosenObject;
    string VarName = "speed";
    public float Price;

    public void OnMouseDown()
    {
        var Instance = ChosenObject.GetComponent<UpgradeValues>();
        var Value = typeof(UpgradeValues).GetField(VarName, BindingFlags.Public | BindingFlags.Instance).GetValue(Instance);
        Value = 100;
    }
}

And the variable lies in this script. It is minimal because I just want to know how to use this for my actual project.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class UpgradeValues : MonoBehaviour
{
    public float speed = 3;
}

I was tried this code and it didn't supply any bugs! But, the variable was simply not converting.

Upvotes: -1

Views: 83

Answers (1)

derHugo
derHugo

Reputation: 90779

Why does yours not work?

Your Value from

var Value = typeof(UpgradeValues).GetField(VarName, BindingFlags.Public | BindingFlags.Instance).GetValue(Instance);

is a simple float (boxed in object). This is a Value type - meaning it is no reference but always a copy of the value in memory - and is in no way at all linked to the underlying field where you originally copied this value from!

So when you do

Value = 100;

all you do is overwriting your local value of your Value variable. This would actually even be the case if your field was a reference type anyway since as said you are just re-assigning your variable, not modifying any property of the thing you stored in it.


(Preferred) Solution

Well you would actually first of all not use Reflection at all in your use case!

You already have the according instance reference

var Instance = ChosenObject.GetComponent<UpgradeValues>();

your field is public so visible to all anyway. So you would rather simply go through

Instance.speed = 100f;

Done!

You could even go further and directly use the correct type for your exposed field and do (you will have to re-assign the field(s))

[SerializeField] private UpgradeValues ChosenObject;

and then simply do

ChosenObject.speed = 100f;

Reflection (don't!)

IF for whatever weird reason you still want to use reflection

You would rather store the FieldInfo reference

var valueField = typeof(UpgradeValues).GetField(VarName, BindingFlags.Public | BindingFlags.Instance);

and then use

valueField.SetValue(Instance, 100f);

but again: I really don't see any reason why you would go for this in your case

Upvotes: 4

Related Questions