1- using System . Collections . Generic ;
21using UnityEditor ;
32using UnityEngine ;
43using System ;
54using System . Linq ;
6- using System . Runtime . Serialization ;
75using System . Reflection ;
8- using System . Text . RegularExpressions ;
96using System . Collections ;
7+ using System . Collections . Generic ;
8+ using System . Runtime . Serialization ;
9+ using System . Text . RegularExpressions ;
1010
1111namespace Core
1212{
1313 [ CustomPropertyDrawer ( typeof ( SerializeExtensionAttribute ) ) ]
1414 public class SerializeExtensionDrawer : PropertyDrawer
1515 {
16- private static LogicAndStack _guiEnableStack = new ( ) ;
16+ private static readonly LogicAndStack _guiEnableStack = new ( ) ;
1717
1818 public override float GetPropertyHeight ( SerializedProperty property , GUIContent label ) {
1919 return property . isExpanded ? EditorGUI . GetPropertyHeight ( property , true ) : EditorGUIUtility . singleLineHeight ;
2020 }
2121
2222 private new SerializeExtensionAttribute attribute => ( SerializeExtensionAttribute ) base . attribute ;
2323
24-
2524 public override void OnGUI ( Rect position , SerializedProperty property , GUIContent label ) {
26- if ( attribute . NameInEditorWindow != null ) {
27- label . text = attribute . NameInEditorWindow ;
28- }
29- if ( attribute . ToolTips != null ) {
30- label . tooltip = attribute . ToolTips ;
31- }
32-
33- Type fieldType = null ;
34- bool isUnityObject = typeof ( UnityEngine . Object ) . IsAssignableFrom ( fieldInfo . FieldType ) ;
35- if ( isUnityObject || fieldInfo . FieldType . IsValueType || property . propertyType != SerializedPropertyType . ManagedReference ) {
36- fieldType = fieldInfo . FieldType ;
37- }
38- else {
39- string [ ] info = property . managedReferenceFieldTypename . Split ( ) ;
40- string asseblyName = info [ 0 ] , typeName = info [ 1 ] ;
41- Assembly assembly = AppDomain . CurrentDomain . GetAssemblies ( ) . FirstOrDefault ( item => item . GetName ( ) . Name == asseblyName ) ;
42- fieldType = assembly . GetType ( typeName ) ;
43- }
44-
45- var owner = GetFieldOwner ( property ) ;
46- PropertyInfo proxy = null ;
47- bool proxyIsValid = false ;
48- if ( attribute . ProxyPropertyName != null && ( fieldType . IsValueType || isUnityObject ) ) {
49- proxy = owner . GetType ( ) . GetProperty ( attribute . ProxyPropertyName , BindingFlags . NonPublic | BindingFlags . Instance | BindingFlags . Public ) ;
50- proxyIsValid = CheckPropertyProxyValid ( proxy , owner , fieldType ) ;
51- }
25+ label . text = attribute . NameInEditorWindow ?? label . text ;
26+ label . tooltip = attribute . ToolTips ?? label . tooltip ;
5227
5328 GUI . enabled = _guiEnableStack . Push ( attribute . CanWrite ) ;
5429 EditorGUI . BeginProperty ( position , label , property ) ;
5530 EditorGUI . BeginChangeCheck ( ) ;
31+
32+ Type fieldType = fieldInfo . FieldType ;
5633 if ( fieldType . IsAbstract || fieldType . IsInterface ) {
57- ShowPolymorphismField ( fieldType , position , property , label ) ;
34+ ShowPolymorphismField ( position , property , label ) ;
5835 }
5936 else {
6037 EditorGUI . PropertyField ( position , property , label , true ) ;
6138 }
6239
6340 bool hasValueUpdated = EditorGUI . EndChangeCheck ( ) || ! attribute . CanWrite ; // !attribute.CanWrite : 当变量不可写时大概率用作显示某个字段的成员信息,为了避免字段发生修改时成员信息更新不同步的问题需要保持更新才行
64- if ( proxyIsValid && hasValueUpdated ) {
65- property . serializedObject . ApplyModifiedProperties ( ) ;
66- if ( proxy . CanRead && proxy . CanWrite ) {
67- proxy . SetValue ( owner , proxy . GetValue ( owner ) ) ;
68- }
69- else if ( proxy . CanRead ) {
70- fieldInfo . SetValue ( owner , proxy . GetValue ( owner ) ) ;
71- }
72- else if ( proxy . CanWrite ) {
73- proxy . SetValue ( owner , fieldInfo . GetValue ( owner ) ) ;
41+ bool canSerializeType = typeof ( UnityEngine . Object ) . IsAssignableFrom ( fieldType ) || fieldType . IsValueType ;
42+ if ( hasValueUpdated && canSerializeType && attribute . ProxyPropertyName != null ) {
43+ var owner = GetFieldOwner ( property ) ;
44+ PropertyInfo proxy = owner . GetType ( ) . GetProperty ( attribute . ProxyPropertyName , BindingFlags . NonPublic | BindingFlags . Instance | BindingFlags . Public ) ; ;
45+ if ( CheckPropertyProxyValid ( proxy , owner , fieldType ) ) {
46+ property . serializedObject . ApplyModifiedProperties ( ) ;
47+ if ( proxy . CanRead && proxy . CanWrite ) {
48+ proxy . SetValue ( owner , proxy . GetValue ( owner ) ) ;
49+ }
50+ else if ( proxy . CanRead ) {
51+ fieldInfo . SetValue ( owner , proxy . GetValue ( owner ) ) ;
52+ }
53+ else if ( proxy . CanWrite ) {
54+ proxy . SetValue ( owner , fieldInfo . GetValue ( owner ) ) ;
55+ }
7456 }
7557 }
58+
7659 GUI . enabled = _guiEnableStack . Pop ( ) ;
7760 EditorGUI . EndProperty ( ) ;
7861 }
7962
8063 #region Show Polymorphism Field
8164 private readonly static Dictionary < Type , List < Type > > _subTypeDict = new ( ) ;
8265
83- private void ShowPolymorphismField ( Type abstractType , Rect position , SerializedProperty property , GUIContent label ) {
66+ private void ShowPolymorphismField ( Rect position , SerializedProperty property , GUIContent label ) {
67+ // 绘制选择框
68+ Type abstractType = fieldInfo . FieldType ;
69+ List < Type > subTypes = GetSubTypes ( abstractType ) ;
70+
8471 Rect labelRect = EditorGUI . IndentedRect ( new ( position ) {
8572 height = EditorGUIUtility . singleLineHeight
8673 } ) ;
8774 Rect popupRect = EditorGUI . PrefixLabel ( labelRect , label ) ;
88- if ( attribute . CanSwitchSubType ) {
89- var subTypes = GetSubTypes ( abstractType ) ;
9075
91- var fieldType = property . managedReferenceValue ? . GetType ( ) ;
92- int currentIndex = subTypes . FindIndex ( type => type == fieldType ) + 1 ; // 会占用选择框0号位置为"None (null)" 所以下标会加一个偏移量
93- string [ ] selectBoxText = subTypes . Select ( type => type . Name ) . Prepend ( "None (null)" ) . ToArray ( ) ;
76+ string [ ] selectBoxTexts = subTypes . Select ( type => type . Name ) . Prepend ( "None (null)" ) . ToArray ( ) ;
77+ Type fieldType = property . managedReferenceValue ? . GetType ( ) ;
78+ int currentIndex = subTypes . FindIndex ( type => type == fieldType ) + 1 ; // 选择框会占用0号位置为 "None (null)" 所以下标会加一个偏移量
9479
95- int newSelectIndex = EditorGUI . Popup ( popupRect , currentIndex , selectBoxText ) ;
96- if ( newSelectIndex != currentIndex ) {
97- if ( newSelectIndex == 0 ) {
98- property . managedReferenceValue = null ;
99- }
100- else {
101- bool hasDefaultConstructor = false ;
102-
103- Type type = subTypes [ newSelectIndex - 1 ] ; // 将选择框的一个偏移量减回来
104- ConstructorInfo [ ] constructors = type . GetConstructors ( ) ;
105- // 查找无参构造函数
106- foreach ( var constructor in constructors ) {
107- if ( constructor . GetParameters ( ) . Length == 0 ) {
108- // 调用无参构造函数并返回实例
109- hasDefaultConstructor = true ;
110- property . managedReferenceValue = constructor . Invoke ( null ) ;
111- }
112- }
113-
114- if ( ! hasDefaultConstructor ) {
115- property . managedReferenceValue = FormatterServices . GetSafeUninitializedObject ( type ) ;
116- }
117- }
118- property . serializedObject . ApplyModifiedProperties ( ) ; //更改多态类型后必须马上保存,否则后续序列化可能会出现异常
80+ GUI . enabled = attribute . CanSwitchSubType ;
81+ int newSelectIndex = EditorGUI . Popup ( popupRect , currentIndex , selectBoxTexts ) ;
82+ GUI . enabled = true ;
83+
84+ if ( newSelectIndex != currentIndex ) {
85+ if ( newSelectIndex == 0 ) {
86+ property . managedReferenceValue = null ;
87+ }
88+ else {
89+ Type type = subTypes [ newSelectIndex - 1 ] ; // 将选择框的一个偏移量减回来
90+ property . managedReferenceValue = CreateInstance ( type ) ;
11991 }
92+ property . serializedObject . ApplyModifiedProperties ( ) ; //更改多态类型后必须马上保存,否则后续序列化可能会出现异常
12093 }
12194
95+ // 绘制序列化字段
12296 Rect foldoutRect = new ( position ) {
12397 height = EditorGUIUtility . singleLineHeight
12498 } ;
@@ -135,30 +109,50 @@ private void ShowPolymorphismField(Type abstractType, Rect position, SerializedP
135109 }
136110 }
137111 }
112+ }
138113
139- static List < Type > GetSubTypes ( Type abstractType ) {
140- if ( ! _subTypeDict . TryGetValue ( abstractType , out var subTypes ) ) {
141- subTypes = AppDomain . CurrentDomain . GetAssemblies ( )
142- . SelectMany ( assembly => assembly . GetTypes ( ) )
143- . Where ( type => abstractType . IsAssignableFrom ( type ) && ! type . IsAbstract && ! type . IsInterface )
144- . ToList ( ) ;
114+ private List < Type > GetSubTypes ( Type abstractType ) {
115+ if ( ! _subTypeDict . TryGetValue ( abstractType , out var subTypes ) ) {
116+ subTypes = AppDomain . CurrentDomain . GetAssemblies ( )
117+ . SelectMany ( assembly => assembly . GetTypes ( ) )
118+ . Where ( type => abstractType . IsAssignableFrom ( type ) && ! type . IsAbstract && ! type . IsInterface )
119+ . ToList ( ) ;
145120
146- const int maxCacheSize = 10 ;
147- while ( _subTypeDict . Count > maxCacheSize ) {
148- _subTypeDict . Remove ( _subTypeDict . Keys . First ( ) ) ;
149- }
150- _subTypeDict . Add ( abstractType , subTypes ) ;
121+ const int maxCacheSize = 10 ;
122+ while ( _subTypeDict . Count > maxCacheSize ) {
123+ _subTypeDict . Remove ( _subTypeDict . Keys . First ( ) ) ;
151124 }
152- return subTypes ;
125+ _subTypeDict . Add ( abstractType , subTypes ) ;
153126 }
127+ return subTypes ;
128+ }
154129
155- //void SetPropertymanagedReferenceValue(List<Type> subTypes, int selectIndex) {
156- // if (selectIndex == curIndex || selectIndex < 0 || selectIndex >= subTypes.Count) return;
157- // property.managedReferenceValue = FormatterServices.GetSafeUninitializedObject(subTypes[selectIndex]);
158- // curIndex = selectIndex;
159- // property.serializedObject.ApplyModifiedProperties(); //更改多态类型后必须马上保存,否则后续序列化可能会出现异常
160- //}
130+ /// <summary>
131+ /// 尝试使用无参构造函数创造实例,若失败则返回未初始化类型
132+ /// </summary>
133+ private object CreateInstance ( Type type ) {
134+ foreach ( var constructor in type . GetConstructors ( ) ) {
135+ if ( constructor . GetParameters ( ) . Length == 0 ) {
136+ return constructor . Invoke ( null ) ;
137+ }
138+ }
139+ return FormatterServices . GetSafeUninitializedObject ( type ) ;
161140 }
141+
142+ //private Type GetRuntimeType(SerializedProperty property) {
143+ // Type fieldType = fieldInfo.FieldType;
144+ // bool canSerializeType = typeof(UnityEngine.Object).IsAssignableFrom(fieldType) || fieldType.IsValueType;
145+ // if (canSerializeType || property.propertyType != SerializedPropertyType.ManagedReference) {
146+ // return fieldInfo.FieldType;
147+ // }
148+ // else {
149+ // string[] info = property.managedReferenceFieldTypename.Split();
150+ // string asseblyName = info[0], typeName = info[1];
151+ // Assembly assembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(item => item.GetName().Name == asseblyName);
152+ // return assembly.GetType(typeName);
153+ // }
154+ //}
155+
162156 #endregion
163157
164158 private object GetFieldOwner ( SerializedProperty property ) {
0 commit comments