¿Es posible iterar a través de varias instancias genéricas y hacer algo con ellas?
public class Dynamic<T> { public T value; public T defaultVal; public void SetDefaultValue() { value = defaultVal; } }¿Es posible hacer que se vea algo como esto:
List<Dynamic<T>> dynamics = new List<Dynamics<T>>(); dynamics.Add(new Dynamic<float>()); dynamics.Add(new Dynamic<Vector2>()); ///... foreach (var item in dynamics) { item.SetDefaultValue(); }Y sí, probablemente sea inútil ya que tengo que insertar manualmente estos valores en esa lista, pero realmente quiero saber si es posible.
Con el modelo de datos que tiene, en C# 2.0 no hay otra forma de hacer lo que quiere que no sea declarando la dynamics como List<object> y usando la reflexión:
List<object> dynamics = new List<object>(); dynamics.Add(new Dynamic<float>()); dynamics.Add(new Dynamic<Vector2>()); foreach (var item in dynamics) { item.GetType().GetMethod("SetDefaultValue").Invoke(item, null); }Realmente no se recomienda, ya que el rendimiento será deficiente y perderá el tiempo de compilación para verificar la corrección.
En su lugar, considere introducir una interfaz no genérica que permita acceder a los miembros requeridos de Dynamic<T> de una manera no genérica:
public interface IDynamic { // Provide read-only access to the Value and DefaultValue as objects: object Value { get; } object DefaultValue { get; } // Set the value to the default value: void SetDefaultValue(); } public class Dynamic<T> : IDynamic { public T value; public T defaultVal; public void SetDefaultValue() { value = defaultVal; } // Use explicit interface implementation because we don't want people to use the non-generic properties when working directly with a specific Dynamic<T>: object IDynamic.Value { get { return value; } } // Note that if T is a struct the value will get boxed object IDynamic.DefaultValue { get { return defaultVal; } } // Note that if T is a struct the value will get boxed }Ahora podrás hacer:
List<IDynamic> dynamics = new List<IDynamic>(); dynamics.Add(new Dynamic<float>()); dynamics.Add(new Dynamic<Vector2>()); foreach (var item in dynamics) { item.SetDefaultValue(); }Extendiendo la respuesta de dbc, para tener las propiedades de su clase almacenadas en una lista para cambiarlas de una vez y por referencia , necesita envolverlas en una clase, para este caso Dynamic<whatever> , porque si tiene tipos primitivos/de valor, esos se copiará en la lista, e incluso los valores de las propiedades se cambian recorriendo la lista, estaría cambiando las copias de la lista y no las propiedades de la clase en sí. Al igual que:
using System; using System.Collections.Generic; using UnityEngine; public class GenericTrial2 : MonoBehaviour { Dynamic<float> vertical = new Dynamic<float> { value = 17, defaultVal = 1 }; Dynamic<Vector2> run = new Dynamic<Vector2> { value = new Vector2(17, 17), defaultVal = Vector2.one }; Dynamic<Quaternion> rotation= new Dynamic<Quaternion> { value = new Quaternion(4,4,4,4), defaultVal = Quaternion.identity }; List<IDynamic> dynamics; private void Start() { dynamics = new List<IDynamic>(); dynamics.Add(vertical); dynamics.Add(run); dynamics.Add(rotation); dynamics.ForEach(prop => { Debug.Log(prop.Value.ToString()); }); Debug.Log($"initValues: vertical: {vertical.value.ToString()}, " + $"run: {run.value.ToString()}, rot: {rotation.value.ToString()} "); } void resetProps() { foreach (var item in dynamics) { item.SetDefaultValue(); } dynamics.ForEach(prop => { Debug.Log(prop.Value.ToString()); }); } private void Update() { if (Input.GetKeyDown(KeyCode.Space)) { resetProps(); Debug.Log($"after reset: vertical: {vertical.value.ToString()}, " + $"run: {run.value.ToString()}, rot: {rotation.value.ToString()} "); } } } public interface IDynamic { // Provide read-only access to the Value and DefaultValue as objects: object Value { get; } object DefaultValue { get; } // Set the value to the default value: void SetDefaultValue(); } public class Dynamic<T> : IDynamic { public T value; public T defaultVal; public void SetDefaultValue() { value = defaultVal; } // Use explicit interface implementation because we don't want people to use the non-generic properties when working directly with a specific Dynamic<T>: object IDynamic.Value { get { return value; } } // Note that if T is a struct the value will get boxed object IDynamic.DefaultValue { get { return defaultVal; } } // Note that if T is a struct the value will get boxed }Producción:
initValues: vertical: 17, run: (17.0, 17.0), rot: (4.0, 4.0, 4.0, 4.0) after reset: vertical: 1, run: (1.0, 1.0), rot: (0.0, 0.0, 0.0, 1.0)