【问题标题】:How can I check if a scriptable object dragged onto inspector is implementing an interface or not?如何检查拖到检查器上的可编写脚本的对象是否正在实现接口?
【发布时间】:2020-07-29 22:48:13
【问题描述】:

对于我的统一项目,我正在尝试制作一个自定义属性抽屉,以使检查器接受仅实现我通过属性参数传递的接口的对象。我很高兴我圆满地完成了 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;
            }
        }
    }

【问题讨论】:

    标签: c# unity3d interface properties drawer


    【解决方案1】:

    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()) 
    {
        ...
    }
    

    【讨论】:

    • 顺便说一句,您可以通过不经常检查这一点来提高效率,而仅在引用更改时将其包装在 EditorGUI.BeginChangeCheck(); var temp_SO = EditorGUI.ObjectField(position, label, property.objectReferenceValue, typeof(ScriptableObject), true); if(EditorGUI.EndChangeCheck()) { .... }
    • 您好,感谢您在那篇文章中提供的帮助。很抱歉通过评论通知您,但您似乎非常擅长 Unity。因此,如果您能检查该问题是否有帮助,我将不胜感激。任何帮助都会奏效。谢谢...stackoverflow.com/questions/63603882/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-06
    • 1970-01-01
    • 2012-04-27
    • 1970-01-01
    • 2012-12-29
    相关资源
    最近更新 更多