【问题标题】:How do I correctly instance a generic class from field type and put it in an array如何正确地从字段类型实例化泛型类并将其放入数组中
【发布时间】:2019-03-25 12:15:16
【问题描述】:

我正在尝试创建MonobehaviourField<T> 类的实例并将其放入monobehaviourFields 数组中。我想使用来自monobehaviourFields 的当前字段中的类型作为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】:

    这可以做到,但您需要稍微更改一下代码。

    1. 您不能拥有MonobehaviourField&lt;object&gt;[] 并在数组中添加一个MonobehaviourField&lt;string&gt;MonoBehaviourField 不是covariant。我已经声明了一个非泛型基类MonobehaviourFieldBase 来解决这个问题。见,例如this question 有类似的问题。

    2. 您需要构造泛型类来创建它的实例,然后使用反射调用构造函数。这里我使用MakeGenericTypeMonobehaviourField&lt;&gt;获取(注意没有指定no类型参数)创建一个MonobehaviourField&lt;T&gt;,其中T是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;
            }
        }
    }
    

    Here is a working example of the code above.

    【讨论】:

    • varConstructedGenericType = typeof(MonobehaviourField).MakeGenericType(fieldType);是否等于 null?
    • 刚用这个类试了一下,不行,构造函数为空public class Tester { public float floatField; public Tester() { } }
    • 好的。我不确定为什么 MakeGenericType 应该返回 null。我明白为什么GetConstructor 会返回null:我犯了一个明显的错字——传入的类型应该始终是typeof(string),而不是fieldType,因为构造函数需要一个字符串。现在我的答案已经解决了。
    • 当字段类型是结构时,我对接口的使用失败,因为您不能以这种方式对结构使用协方差(例如link),所以我选择了基类,@ 987654346@,而不是。更新后的示例有一个string(类)字段和一个float(结构)字段,适用于两者。
    猜你喜欢
    • 1970-01-01
    • 2021-07-09
    • 2013-10-03
    • 2011-04-02
    • 1970-01-01
    • 2021-12-06
    相关资源
    最近更新 更多