【发布时间】:2019-11-07 18:59:42
【问题描述】:
我正在写一个扩展方法来简化SerializedProperty的使用
这个想法是该方法的用户应该能够设置SerializedProperty 的值,而不必担心类型。如下例所示,正确的类型应该根据serializedProperty和myValue的类型来处理。
SerializedProperty的常规使用示例,Unity方式:
serializedProperty.intValue = myIntValue;
serializedProperty.floatValue = myFloatValue;
serializedProperty.boolValue = myBoolValue;
...
SerializedProperty 方法扩展的预期语法
serializedProperty.SetValue(myValue);
我目前对此SerializedProperty 方法扩展的实现
public static void SetValue<TValue>(this SerializedProperty property, TValue value)
{
if (property.hasMultipleDifferentValues)
throw new ArgumentOutOfRangeException();
Type parentType = property.serializedObject.targetObject.GetType();
FieldInfo fieldInfo = parentType.GetField(property.propertyPath);
fieldInfo.SetValue(property.serializedObject.targetObject, value);
}
问题:
此实现不调用 OnValidate Unity 回调。常规用法 (mySerializedProperty.intValue = myInt) 可以。
我的问题:有什么方法可以强制 Unity 在 SerializedProperty 上调用 OnValidate 方法?
我考虑过自己通过反射调用 OnValidate,但由于这已经在 Unity 中实现,我想知道是否有办法将 SerializedProperty 标记为已更改或类似的东西。
为了测试这种行为,我编写了以下测试(NUnit):
private IntMonoBehaviourMock _mockInstance;
[SetUp]
public void CallBeforeEachTest()
{
GameObject gameObject = new GameObject();
this._mockInstance = gameObject.AddComponent<IntMonoBehaviourMock>();
}
[Test]
// This test fails for the current implementation
public void SetValue_ToDifferentValue_OnValidateCalledOnce()
{
this.SetValueOfSUT(0x1CE1CE);
int numCallsBefore = this._mockInstance.NumTimesValidateCalled;
this.SetValueOfSUT(0xBABE);
int numCallsAfter = this._mockInstance.NumTimesValidateCalled;
int actualNumCalls = numCallsAfter - numCallsBefore;
Assert.AreEqual(1, actualNumCalls); // Fails
}
private void SetValueOfSUT(int value)
{
string fieldName = "publicSerializedField"
SerializedObject serializedObject = new SerializedObject(this._mockInstance);
SerializedProperty sut = this._serializedObject.FindProperty(fieldName);
// This is the call to function being tested!
// Swapping this for sut.intValue = value, makes the test pass.
// (But the purpose is to write a function that handles any type correctly)
sut.SetValue(value);
this._serializedObject.ApplyModifiedProperties();
}
我在测试中使用的IntMonoBehaviourMock的实现是:
public class IntMonoBehaviourMock: MonoBehaviour
{
[SerializeField]
public int publicSerializedField = default;
public int NumTimesValidateCalled { get; private set; }
protected void OnValidate()
{
this.NumTimesValidateCalled++;
}
}
测试结果是:
Expected: 1
But was: 0
【问题讨论】:
标签: c# unity3d serialization