如何检查拖到检查器上的可编写脚本的对象是否正在实现接口?

How can I check if a scriptable object dragged onto inspector is implementing an interface or not?

对于我的统一项目,我正在尝试制作一个自定义 属性 抽屉,以使检查器接受仅实现我通过属性参数传递的接口的对象。我很高兴我圆满地完成了 MonoBehaviour 对象的任务。但是,我在对可编写脚本的对象应用类似方法时遇到了麻烦。我需要帮助。

这是我的 属性 抽屉代码。问题是 C# 不允许我使用“is”关键字进行类型检查。这是我试过的一些代码

 if(temp_SO is requiredAttribute.requiredType) {}
 if(temp_SO is T) {}
 if(temp_SO.GetType().Equals(requiredAttribute.requiredType) {}

但都失败了... 但是,正如下面的代码所示,如​​果我将其硬编码为 if(temp_SO is interface_C) 那么它就可以工作。我找不到动态传递类型值的方法。因为 IDE 不断抛出“预期为常数值”错误。任何帮助将不胜感激。谢谢..

 [CustomPropertyDrawer(typeof(SOInterfaceExposeAttribute))]
    public class SOInterfaceExposeAttributeDrawer : PropertyDrawer
    {
        Type T;
        public override void OnGUI ( Rect position , SerializedProperty property , GUIContent label )
        {
            if ( property . propertyType == SerializedPropertyType . ObjectReference )
            {
                var requiredAttribute = this . attribute as SOInterfaceExposeAttribute;
    
                T = requiredAttribute . requiredType;
            
                var lastValidRef = property . objectReferenceValue;
    
                EditorGUI . BeginProperty(position , label , property);
    
                ScriptableObject temp_SO = EditorGUI . ObjectField(position , label , property . objectReferenceValue , typeof(ScriptableObject) , true) as ScriptableObject;
    
                // Finish drawing property field.
                if ( temp_SO != null )
                {
                    if ( temp_SO is Interface_C)
                    {
                        Debug . Log("interface component found");
                        property . objectReferenceValue = temp_SO as ScriptableObject;
                    }
                    else
                    {
                        Debug . Log("interface component NOT found");
                        property . objectReferenceValue = lastValidRef;
                    }
                }
    
                EditorGUI . EndProperty();
            }
            else
            {
                // If field is not reference, show error message.
                // Save previous color and change GUI to red.
                var previousColor = GUI . color;
                GUI . color = Color . red;
                // Display label with error message.
                EditorGUI . LabelField(position , label , new GUIContent("Property is not a reference type"));
                // Revert color change.
                GUI . color = previousColor;
            }
        }
    }

is确实需要常量类型参数。

你试过的另一种方式

if(temp_SO.GetType().Equals(requiredAttribute.requiredType)

不会工作,因为这两种类型肯定 相等,因为一个实现了另一个 ;)


你或许可以使用 IsInstanceOfType

var temp_SO = EditorGUI.ObjectField(position, label, property.objectReferenceValue, typeof(ScriptableObject), true);

// Finish drawing property field.
if (temp_SO != null)
{
    if (requiredAttribute.requiredType.IsInstanceOfType(temp_SO))
    {
        Debug.Log("interface component found");
        property.objectReferenceValue = temp_SO;
    }
    else
    {
        Debug.Log("interface component NOT found");
        property.objectReferenceValue = lastValidRef;
    }
}

IsAssignableFrom喜欢

var temp_SO = EditorGUI.ObjectField(position, label, property.objectReferenceValue, typeof(ScriptableObject), true);

// Finish drawing property field.
if (temp_SO != null)
{
    if (requiredAttribute.requiredType.IsAssignableFrom(temp_SO.GetType()))
    {
        Debug.Log("interface component found");
        property.objectReferenceValue = temp_SO;
    }
    else
    {
        Debug.Log("interface component NOT found");
        property.objectReferenceValue = lastValidRef;
    }
}

另一种方法是使用 FindInterfaces 来比较是否有任何继承类型实现了接口类型

var temp_SO = EditorGUI.ObjectField(position, label, property.objectReferenceValue, typeof(ScriptableObject), true);

// Finish drawing property field.
if (temp_SO != null)
{
    // Filter taken from the linked examples
    if (temp_SO.GetType().FindInterfaces(new TypeFilter((type, criteria) => type.ToString() == criteria.ToString()), requiredAttribute.requiredType.Name()).Length > 0)
    {
        Debug.Log("interface component found");
        property.objectReferenceValue = temp_SO;
    }
    else
    {
        Debug.Log("interface component NOT found");
        property.objectReferenceValue = lastValidRef;
    }
}

顺便说一句,您可以通过不经常检查它来提高效率,而是仅在引用更改时将其包装在

EditorGUI.BeginChangeCheck(); 
var temp_SO = EditorGUI.ObjectField(position, label, property.objectReferenceValue, typeof(ScriptableObject), true); 
if(EditorGUI.EndChangeCheck()) 
{
    ...
}