首页 > 解决方案 > 如何正确地从字段类型实例化泛型类并将其放入数组中

问题描述

我正在尝试创建MonobehaviourField<T>该类的一个实例并将其放入monobehaviourFields数组中。我想使用当前字段中的类型monobehaviourFieldsas T。这条线

monobehaviourFields[i] = new MonobehaviourField<typeof(fieldType)>("test");

不工作。如何根据 fieldType 创建一个实例并将其放入数组中?

using UnityEngine;
using System.Reflection;
using System;
using System.Linq;

[Serializable]
public class MonobehaviourWrapper
{
    private MonobehaviourField<object>[] monobehaviourFields;

    public MonobehaviourWrapper(FieldInfo[] fields)
    {
        monobehaviourFields = new MonobehaviourField<object>[fields.Length];
        for (int i = 0; i < monobehaviourFields.Length; i++)
        {
            Type fieldType = fields[i].FieldType;
            monobehaviourFields[i] = new MonobehaviourField<typeof(fieldType)>("test");
        }
    }

    [Serializable]
    public class MonobehaviourField<T>
    {
        [SerializeField] private string fieldName;
        [SerializeField] private T objectContainer;
        [SerializeField] private string typeName;

        public MonobehaviourField(string fieldName)
        {
            this.fieldName = fieldName;
            this.typeName = typeof(T).FullName;
        }

        public Type FieldType { get { return Type.GetType(typeName); } }
        public T ObjectContainer { get { return objectContainer; } set { objectContainer = value; } }
        public string FieldName { get { return fieldName; } set { fieldName = value; } }
    }
}

标签: c#generics

解决方案


这可以完成,但您需要稍微更改代码。

  1. 你不能有一个MonobehaviourField<object>[]并添加,比如 aMonobehaviourField<string>到数组:MonoBehaviourFieldis not covariant。我已经声明了一个非泛型基类MonobehaviourFieldBase来解决这个问题。参见,例如这个问题,它有一个类似的问题。

  2. 您需要构造泛型类以创建它的实例,然后使用反射调用构造函数。这里我使用MakeGenericType来获取MonobehaviourField<>(注意没有指定类型参数)来创建一个MonobehaviourField<T>where T is fieldType。然后我Type.GetConstructor用来获取相关的构造函数,并ConstructorInfo.Invoke实际调用构造函数。请注意,它Invoke返回一个类型的实例,Object因此需要将其强制转换为要添加到数组的接口。

这是代码(请注意,为简洁起见,我删除了不属于您的问题的代码部分):

public class MonobehaviourWrapper
{
    private MonobehaviourFieldBase[] monobehaviourFields;

    public MonobehaviourWrapper(FieldInfo[] fields)
    {
        monobehaviourFields = new MonobehaviourFieldBase[fields.Length];

        for ( int i = 0; i < monobehaviourFields.Length; i++ )
        {
            Type fieldType = fields[i].FieldType;
            var constructedGenericType = typeof(MonobehaviourField<>).MakeGenericType(fieldType);
            var constructor = constructedGenericType.GetConstructor(new Type[] { typeof(string) });

            object resultOfConstructor = constructor.Invoke(new object[] { "This code has worked" });
            monobehaviourFields[i] = (MonobehaviourFieldBase)resultOfConstructor;
        }
    }

    public IEnumerable<MonobehaviourFieldBase> MonobehaviourFields
    {
        get
        {
            return monobehaviourFields;
        }
    }

    public class MonobehaviourField<T> : MonobehaviourFieldBase
    {
        public MonobehaviourField(string name)
        {
            FieldName = name;
        }
    }
}

和基类:

public class MonobehaviourFieldBase
{
    private string fieldName;

    public string FieldName
    {
        get
        {
            return fieldName;
        }
        set
        {
            fieldName = value;
        }
    }
}

这是上面代码的一个工作示例


推荐阅读