Editing a List Propertyfield in Editor Extension overwrites previously saved entries. How to fix?

I have an editor window that I am using to create new rules for a rulebook. I create rules by selecting some options, filling in some fields, etc, and then I click Save Rule.

One of those options is a Propertyfield List.

List<Criterion> conditionsToBeMet = new List<Criterion>();

The whole system works fine until I try to save more than one rule. What seems to happen is that editing the options for the List changes those options for the previously saved rules instead of just for the new rule I’m making.

As a result, the List part of all the rules is constantly being overwritten whenever I change any part of the List.

Any ideas why this is happening and how to fix it?

Here’s my code for the editor window:

using UnityEngine;
using UnityEditor;
using System.Collections;
using System.Collections.Generic;

public class RuleEditor : EditorWindow {
	List<Criterion> conditionsToBeMet = new List<Criterion>();
	string newWhoID = "someone";
	Concepts newConcept = 0;
	string combinedCriteria = "no other conditions are met";
	Responses newResponse = 0;
	string newActionValue = "some value";

	[MenuItem ("Window/Rulebook")]

	public static void  ShowWindow () {

	void OnGUI()
		//Add a Rule
		GUILayout.Label ("Add New Rule", EditorStyles.boldLabel);
		if(conditionsToBeMet.Count == 0)
		{	//If we have no criteria at all, fill in the criteria in the visualized rule display with filler text
			combinedCriteria = "no other conditions are met";
			int index = 0;
			foreach(Criterion c in conditionsToBeMet)
				if(index != 0)
				{	//Here we add an understandable language to show these conditions are being concatenated and thus must all be true to met the requirements for the rule
					combinedCriteria += " and also " + c;
					combinedCriteria = c.ToString();

				//Make sure that we don't do anything illegal in Criterion construction. In other words, always make sure a min value is never greater than max.
				if(c.minValToCompare > c.maxValToCompare)
					c.minValToCompare = c.maxValToCompare;

				//Finally, move on to the next criterion

			//Make sure we can see in plain text what our new Rule will look like
		GUILayout.Label ("New Rule Logic: "+"When "+newWhoID+" "+newConcept+" and "+combinedCriteria+", then "+newResponse+" by "+newActionValue, EditorStyles.label);

			//Start the Rule editable fields
		newWhoID = EditorGUILayout.TextField("Subject:", newWhoID);
		newConcept = (Concepts)EditorGUILayout.EnumPopup ("Condition Verb:", newConcept);

			//Necessary serializable stuff for PropertyField to work correctly
		ScriptableObject target = this;
		SerializedObject so = new SerializedObject(target);
		SerializedProperty criteriaProperty = so.FindProperty("conditionsToBeMet");
		EditorGUILayout.PropertyField (criteriaProperty, true);

			//Finish up the Rule editable fields
		newResponse = (Responses)EditorGUILayout.EnumPopup ("Response Verb:", newResponse);
		newActionValue = EditorGUILayout.TextField("Amount of Response:", newActionValue);

			//A button to allow the new Rule to be added to the list
		if(GUILayout.Button("Save Rule"))
			//TODO: There is currently a bug where new rules will have the same Criteria list as the old rules

			List<Criterion> newConditions = new List<Criterion>(conditionsToBeMet);

			//Turn the WhoID string into an actual WhoID reference and create a new Rule from the data
			Rule newRule = new Rule (RuleLogic.GetWhoID(newWhoID), newConcept, newConditions, newResponse, newActionValue);
		//Rule List
		GUILayout.Label ("Rulebook", EditorStyles.boldLabel);
		int selected = 0;
		List<string> optionsList = new List<string> ();

			//Show the Rule list as a pop-out drop down
		foreach(Rule rule in GlobalLists.ruleBook)
			string ruleString = rule.ToString ();
			optionsList.Add (ruleString);
		string[] options = optionsList.ToArray ();
		selected = EditorGUILayout.Popup("Rule List:", selected, options);


Well, the problem is pretty simple. You have one list instance inside your editor window “conditionsToBeMet”. This list is edited by your propertyfield GUI. In there by changing the list count you will create new instances of your “Criterion” class. When you “save” / create your rule you copy the elements from your “conditionsToBeMet” list into a new lsit which is passed to the rule instance and probably saved inside the rule instance. However both lists will reference the same “Criterion” class instances. So using one list to access a Criterion instance and applying changes to it would be visible from the second List as well since they both have the same elements.

You should not copy the List into a new list but simply pass the current list to your rule and then create a new empty list:

 if(GUILayout.Button("Save Rule"))
     Rule newRule = new Rule (RuleLogic.GetWhoID(newWhoID), newConcept, conditionsToBeMet, newResponse, newActionValue);

     // create new empty list
     conditionsToBeMet = new List<Criterion>();

That way the old list and it’s Criterion instances now belongs to your newRule instance and the “conditionsToBeMet” variable gets a new list for the next rule. You also might want to “reset” the other temp variables as well (newWhoID, newConcept, newResponse, newActionValue) unless you specifically want to keep them for the next rule