Are namespaces supported in Unity 4?

So apparently MonoBehaviours should be able to be in a namespace in U4. However, I get a lot of warnings about the “The class defined in script file ‘x’ does not match the filename” - is there something I can do about this?

EDIT: Just to be clear

  • The warning only happens if the class is in a namespace

With the namespace:

[5690-screen+shot+2012-12-11+at+09.02.30.jpg|5690]

Without the namespace:

[5691-screen+shot+2012-12-11+at+09.03.17.jpg|5691]

The code (with the namespace):

Here’s the code:

using System;
using UnityEngine;

namespace RadicalLibrary
{
	
	public class ActivatedObject : StateMachineBehaviour, IMessage, IAmActivated
	{
		public string message;
		public string activatedMessage;
		public string Name = "Take 001";
		public bool touchEnabled = true;
		public float Speed = 1;
		private StateMachine _sm;
		public GameObject targetObject;
		
		public bool IsActivated()
		{
			return Activated;
		}
		
		private bool _activated;
		public bool Activated {
			get {
				return _activated;
			}
			set {
				_activated = value;
				var go = targetObject == null ? gameObject : targetObject;
				if (!String.IsNullOrEmpty (Name)) {
					if (value) {
						go.animation [Name].speed = Speed;
						go.animation.Play (Name);
					} else {
						if (go.animation [Name].time == 0) {
							go.animation [Name].time = go.animation [Name].length;
						}
						go.animation [Name].speed = -Speed;
						go.animation.Play (Name);
					}
				}
			}
			
		}
		
		void TouchActivated()
		{
			Activated = !Activated;
		}
		
		
		#region IMessage implementation
		public string GetMessage ()
		{
			return Activated ? activatedMessage : message;
		}
		#endregion
	
		
	}
	
	public class WaitForRelease : State
	{
			
		private Action _action;
	
		public WaitForRelease (Action actionOnRelease = null)
		{
			_action = actionOnRelease;
			
		}
			
		public override void OnUpdate ()
		{
			if (TouchInterface.TouchCount == 0) {
				SetState (StateMachine.Inactive);
				if (_action != null) {
					_action ();
				}
			}
		}
			
	}
	
}

Here’s one more that took us a long time to figure out: MonoBehaviours inside namespaces break, if they have a method with a default parameter (such as public void Foo(bool bar=true)).

I just wanted to add that anything can break it; I had an enum in one of mine driving me crazy trying to fix.

One more thing, [ExecuteInEditMode] breaks the class as well - I wouldn’t be surprised if other, similar flags break things.

Here’s the answer:

  • If there are two classes in a file then it works fine without a namespace
  • If there are two classes in a file then putting them both in a namespace fails
  • If, in the example, I put WaitForRelease as a child of ActivatedObject it works fine, so nested classes work
  • If the class has methods with default parameters it fails [Added due to answer below]

So for me it wasn’t just default params, but also named params! (i.e. namespaces AND named params - if you use either one alone you shouldn’t have problems)

This will fail:

namespace MyNamespace
{
   public class Settings : ScriptableObject
   {
		public static void IntMethod(int x) { }
		public static void Test()
		{
			IntMethod(@x: 10); // <-- Named param
		}
   }
}

// Somewhere else...
Debug.Log(ScriptableObject.CreateInstance<Settings>()); // prints "()"

This will succeed:

namespace MyNamespace
{
   public class Settings : ScriptableObject
   {
		public static void IntMethod(int x) { }
		public static void Test()
		{
			IntMethod(10); // <-- Pass arg normally
		}
   }
}

// Somewhere else...
Debug.Log(ScriptableObject.CreateInstance<Settings>()); // prints a valid value

#What Works (4.5.5+)#

I came across this issue in testing with versions of Unity between 4.5.5 and 5.1.1. It seems that the following are no longer limitations (in at least 4.5.5+):

  • Two classes in the same file, both within a namespace.
  • Having a method with a default parameter within the MonoBehaviour/ScriptableObject subclass that’s in a namespace.

I have not tested with named parameters and therefore cannot speak to them.

#What Doesn’t Work (as late as 5.1.1)#

However, I did run afoul of an issue with namespaces and MonoBehaviours/ScriptableObjects. The following WILL NOT WORK:

  • A non-MonoBehaviour/ScriptableObject class that has a method with a default parameter appears before the MonoBehaviour/ScriptableObject subclass in the script file.

The following examples are expected to be in a file called TestClass.cs.

##Works: No Namespaces##

The SupportClass is simply a wrapper for an int. This works.

using UnityEngine;

[System.Serializable]
public class SupportClass
{
	public int anInt;

	public void SetTheInt(int i = 1)
	{
		anInt = i;
	}
}

public class TestClass : MonoBehaviour
{
	public SupportClass someVal;

	public int TestMethod(int i = 1)
	{
		return i;
	}
}

##Doesn’t Work: Add a Namespace##

Both classes are within the namespace.

using UnityEngine;

namespace TestNamespace
{
	[System.Serializable]
	public class SupportClass
	{
		public int anInt;

		public void SetTheInt(int i = 1)
		{
			anInt = i;
		}
	}

	public class TestClass : MonoBehaviour
	{
		public SupportClass someVal;

		public int TestMethod(int i = 1)
		{
			return i;
		}
	}
}

##Works: Reorder Classes Within the Namespace##

Simply changing the order of the classes causes this to work again.

using UnityEngine;

namespace TestNamespace
{
	public class TestClass : MonoBehaviour
	{
		public SupportClass someVal;
		
		public int TestMethod(int i = 1)
		{
			return i;
		}
	}

	[System.Serializable]
	public class SupportClass
	{
		public int anInt;

		public void SetTheInt(int i = 1)
		{
			anInt = i;
		}
	}
}

##Works: Remove the Default Parameter from the Support Class##

Simply removing the default parameter from the support class when it appears first, also fixes the problem.

using UnityEngine;

namespace TestNamespace
{
	[System.Serializable]
	public class SupportClass
	{
		public int anInt;

		public void SetTheInt(int i)
		{
			anInt = i;
		}
	}

	public class TestClass : MonoBehaviour
	{
		public SupportClass someVal;

		public int TestMethod(int i = 1)
		{
			return i;
		}
	}

#Final Note#

You can have multiple support classes defined before the MonoBehaviour/ScriptableObject subclass. This will work 100% fine until you add a default parameter to any method in any support class that appears in the script file before the MonoBehaviour/ScriptableObject subclass. In fact, if you have multiple support classes, you can put those without default parameters in their methods before the MonoBehaviour/ScriptableObject subclass and those with them after. This also works fine.