Как я могу получить имя поля из метода, используя отражение?

#c# #unity3d #system.reflection

Вопрос:

Я впервые экспериментирую с отражением в c# (для использования в инструменте разработки, который я создаю), и мне было интересно, может ли кто-нибудь помочь мне получить доступ к тому, к чему я пытаюсь получить доступ?

Приведенный ниже код-это класс, к которому я обращаюсь:

 [Serializable]
public class MaterialVariantTarget : BaseNode, IMaterialTarget
{
   public MeshRenderer m_Target;
   public void ApplyValue(Material value) => m_Target.material = value;
}
 

Вопрос, на который я хочу ответить, заключается в том, как называется значение, с которым работает функция ApplyValue (). Так что в этом примере это будет MeshRenderer.material

Я разбил проблему на две части. Доступ к типу m_Target (MeshRenderer) и свойству .material.

Во-первых, мне удалось получить доступ:

 private Type GetTargetComponentType(Type targetNodeType)
{
    foreach (var fieldInfo in targetNodeType.GetFields())
    {
        if (fieldInfo.Name == "m_Target")
        {
            var type = fieldInfo.FieldType;
            return type;
        }
    }

    return null;
}
 

Я нахожу доступ к части scond более сложным. Возможно ли вообще то, что я пытаюсь сделать, и если да, то как я могу это сделать?

большое спасибо


[ОБНОВЛЕНИЕ]

Таким образом, кажется, что консенсус состоит в том, что я не могу получить доступ к содержимому метода.

Мне придется просто прибегнуть к написанию необходимой мне информации в виде строки, которую затем можно будет прочитать, но она не идеальна 🙁

Могло бы у меня быть больше возможностей, если бы я организовал его как средство получения/настройки свойств? подобный этому:

 [Serializable]
    public class MaterialVariantTarget : BaseNode, IMaterialTarget
    {
        public MeshRenderer m_Target;

        private Material m_valueProperty
        {
            get => m_Target.material;
            set => m_Target.material = value;
        }
        
        public void ApplyValue(Material value) => m_valueProperty = value;
}
 

Комментарии:

1. так m_Target может быть разного типа в зависимости от класса? Если он всегда имеет тип MeshRenderer , все, что вам нужно сделать, это бросить его

2. То, что вам нужно, потребует декомпиляции IL.

3. И m_Target то и другое и .material могло быть по-другому. Так, например, у меня есть еще один, в котором есть Transform и .localPosition . Я думаю, я мог бы просто добавить строку const, которая явно перечисляет MeshRenderer.material , но это делает вещи немного более хрупкими, так как мне нужно будет запомнить, чтобы а) заполнить это и б) обновить его, если что-то изменится в будущем 🙁

4. Я не думаю, что ты сможешь

5. Спасибо, я обновил вопрос, возможно, с помощью нового подхода?

Ответ №1:

Вот два удобных расширения, которые я создал для извлечения значения поля или свойства объекта на основе имени или типа:

 public static class Extensions
{
    public static object GetPropertyOrFieldByName(this object obj, string nameToSearch)
    {
        foreach (var field in obj.GetType().GetFields())
        {
            if (field.Name == nameToSearch)
            {
                return field.GetValue(obj);
            }
        }

        foreach (var property in obj.GetType().GetProperties())
        {
            if (property.Name == nameToSearch)
            {
                return property.GetValue(obj);
            }
        }

        return null;
     }

    public static T GetPropertyOrFieldByType<T>(this object obj) where T : Object
    {
        foreach (var field in obj.GetType().GetFields())
        {
            if (field.FieldType == typeof(T))
            {
                return (T)field.GetValue(obj);
            }
         }

        foreach (var property in obj.GetType().GetProperties())
        {
            if (property.PropertyType == typeof(T))
            {
                return (T)property.GetValue(obj);
            }
        }

        return null;
    }
}
 

Использование, которое вам требуется, может быть реализовано таким образом:

 object target = yourMaterialVariantTarget.GetPropertyOrFieldByName("m_Target");
Material material = target.GetPropertyOrFieldByType<Material>();
material.color = Color.red;
 

Комментарии:

1. эй, извини, что не вернулся к этому 🙂

2. Хотя это хорошее решение для доступа к значению поля, к сожалению, это не совсем те данные, к которым я пытался получить доступ. В этом решении мне нужно было бы заранее знать, что свойство, которое я искал, относится к типу материала .

3. То, на чем я застрял, — это попытка определить имя этого поля (не зная его типа заранее) на основе отражаемого класса. Таким образом, в одном случае это может быть свойство типа Material , называемое material , в компоненте MeshRenderer, а в другом-свойство типа Vector3 , называемое localPosition , из компонента преобразования . Также возможно, что мы могли бы быть свойством localScale, к которому я пытаюсь получить доступ в том же компоненте преобразования , который также будет иметь тип Vector3 , поэтому, к сожалению, знание типа не решает проблему.

4. Последнее, что следует отметить, — это то, что на самом деле мне не нужна стоимость недвижимости. Я ищу название объекта недвижимости. таким образом, моим идеальным возвратом был бы материал / локальное расположение / локальный масштаб в виде строки.

5. @RobertJHomewood честно говоря, вам следует переписать вопрос, объяснив, чего вы намерены достичь и почему, и предоставить несколько примеров примеров. В нынешнем виде это немного сбивает с толку.