Using C# dynamic typing with Unity 4.3.4f1

I have written generic GUi framework in C# that uses dependency injection to run on almost any platform.

I am trying t port it to Unity3D right now but I have run into issues. I have a nice, clean generic vector class that uses dynamic to implement the overloaded operators. Unity complained about the implicit type coercion first, so i fixed that and made it explicit. I also changed the .NEt version from 2.0 Subset to 2.0 in client perferences.

Now it compiles but I get the following error from the Internals:

Internal compiler error. See the console log for more information. output was:error CS0518: The predefined type `System.Runtime.CompilerServices.CallSite’ is not defined or imported

error CS0518: The predefined type System.Runtime.CompilerServices.CallSite1’ is not defined or imported
error CS0518: The predefined type System.Runtime.CompilerServices.CallSite' is not defined or imported error CS0518: The predefined type System.Runtime.CompilerServices.CallSite1' is not defined or imported error CS0518: The predefined type System.Runtime.CompilerServices.CallSite’ is not defined or imported

Id appreciate any thoughts on how to make this work.

Here’s an example of the code:

public struct Vector2<T> where T: struct {

	public Vector2(T x, T y):this(){
		X = x;
		Y = y;
	}

	public T X {
		get ;
		set ;
	}

	public T Y {
		get ;
		set ;
	}

	public static Vector2<T> operator +(Vector2<T> lhs, Vector2<T> rhs) 
	{
		return new Vector2<T>((T)((dynamic)lhs.X+rhs.X),(T)((dynamic)lhs.Y+rhs.Y));
	}


(etc ... )

You’re not allowed to use the “dynamic” keyword at all; Unity uses a very old version of Mono that won’t compile any of the newer syntax that was introduced in .NET 4.

To get around it, I’d suggest casting to a double, doing the addition, then casting back to T. That should be safe for all built-in numeric types at least.

So, as suggested, this was my answer. Its nasty on a couple of levels but it will work…

using System;

/// <summary>
/// This class imp[lements various useful math functions

/// </summary>
namespace WWUtils.Math
{

	/// <summary>
	/// This is a hack that treats all numbers as doubles.  Its temporary because
	/// Unity does not support dynamic properly
	/// </summary>
	public struct Vector2<T> where T: struct {
	
		internal double x;
		internal double y;
		public Vector2(T x, T y):this(){
			X = x;
			Y = y;
		}

		private static T ConvertFrom(double v){
			return (T)(object)v;
		}

		private static double ConvertTo(T v){
			return (double)(object)v;
		}

		public T X {
			get {return ConvertFrom(x);}
			set {x=ConvertTo(value);}
		}

		public T Y {
			get {return ConvertFrom(y);}
			set {y=ConvertTo(value);}
		}

		public static Vector2<T> operator +(Vector2<T> lhs, Vector2<T> rhs) 
		{
			return new Vector2<T>(ConvertFrom(lhs.x+rhs.x),
			                      ConvertFrom(lhs.y+rhs.y));
		}

		public static Vector2<T> operator -(Vector2<T> lhs, Vector2<T> rhs) 
		{
			return new Vector2<T>(ConvertFrom(lhs.x-rhs.x),
			                      ConvertFrom(lhs.y-rhs.y));
		}

		public static Vector2<T> operator *(Vector2<T> lhs, T scaler) 
		{
			return new Vector2<T>(ConvertFrom(lhs.x*ConvertTo(scaler)),
			                      ConvertFrom(lhs.y*ConvertTo(scaler)));
		}

		public static Vector2<T> operator /(Vector2<T> lhs, T scaler) 
		{
			return new Vector2<T>(ConvertFrom(lhs.x/ConvertTo(scaler)),
			                      ConvertFrom(lhs.y/ConvertTo(scaler)));
		}

		/// <summary>>
		/// Dot product
		/// </summary>
		/// <param name="lhs">Lhs.</param>
		/// <param name="rhs">Rhs.</param>
		public T Dot(Vector2<T> rhs){
			return ConvertFrom((x * rhs.x) + (y * rhs.y));
		}

		public Vector2<T> Rotate(float deg){
			float rad = (float)(deg * System.Math.PI / 180);
			float s = (float)System.Math.Sin(rad);
			float c = (float)System.Math.Cos(rad);

			return new Vector2<T>(ConvertFrom((x * c) - (y * s)),
				ConvertFrom((x * s) + (y * c)));
		}

		public override string ToString ()
		{
			return string.Format ("[Vector2("+X+","+Y+")]");
		}

		public static implicit operator Vector2<T>(Vector3<T> someValue)
		{
			return new Vector2<T>(someValue.X,someValue.Y);
		}
	}

	public struct Vector3<T> where T: struct {

		double x;
		double y;
		double z;
		public Vector3(T x, T y, T z):this(){
			X = x;
			Y = y;
			Z = z;
		}

		private static T ConvertFrom(double v){
			return (T)(object)v;
		}
		
		private static double ConvertTo(T v){
			return (double)(object)v;
		}

		public T X {
			get {return ConvertFrom(x);}
			set {x=ConvertTo(value);}
		}
		
		public T Y {
			get {return ConvertFrom(y);}
			set {y=ConvertTo(value);}
		}

		public T Z {
			get {return ConvertFrom(z);}
			set {z=ConvertTo(value);}
		}

		public static Vector3<T> operator +(Vector3<T> lhs, Vector3<T> rhs) 
		{
			return new Vector3<T>(ConvertFrom(lhs.x+rhs.x),
			                      ConvertFrom(lhs.y+rhs.y), 
			                      ConvertFrom(lhs.z+rhs.z));
		}

		public static Vector3<T> operator -(Vector3<T> lhs, Vector3<T> rhs) 
		{
			return new Vector3<T>(ConvertFrom(lhs.x-rhs.x),
			                      ConvertFrom(lhs.y-rhs.y), 
			                      ConvertFrom(lhs.z-rhs.z));
		}

		public static Vector3<T> operator *(Vector3<T> lhs, T scaler) 
		{
			return new Vector3<T>(ConvertFrom(lhs.x*ConvertTo(scaler)),
					              ConvertFrom(lhs.y*ConvertTo(scaler)), 
					              ConvertFrom(lhs.z*ConvertTo(scaler)));
		}

		public static Vector3<T> operator /(Vector3<T> lhs, T scaler) 
		{
			return new Vector3<T>(ConvertFrom(lhs.x/ConvertTo(scaler)),
			                      ConvertFrom(lhs.y/ConvertTo(scaler)),
			                      ConvertFrom(lhs.z/ConvertTo(scaler)));
		}

		///<summary>
		/// The cross product
		///  cx = aybz - azby
		///  cy = azbx - axbz
		///  cz = axby - aybx
		/// </summary>
		/// <param name="lhs">Lhs.</param>
		/// <param name="rhs">Rhs.</param>
		public static Vector3<T> operator *(Vector3<T> lhs, Vector3<T> rhs) 
		{
			T cx = ConvertFrom((lhs.y * rhs.z) - (lhs.z * rhs.y));
			T cy = ConvertFrom((lhs.z * rhs.x) - (lhs.x * rhs.z));
			T cz = ConvertFrom((lhs.x * rhs.y) - (lhs.y * rhs.x));
			return new Vector3<T> (cx, cy, cz);
		}

		/// <summary>>
		/// Dot product
		/// </summary>
		/// <param name="lhs">Lhs.</param>
		/// <param name="rhs">Rhs.</param>
		public T Dot(Vector3<T> rhs){
			return ConvertFrom((x * rhs.x) + (y * rhs.y)+ (z * rhs.z));
		}

		public override string ToString ()
		{
			return string.Format ("[Vector3("+X+","+Y+","+Z+")]");
		}

		public static implicit operator Vector3<T>(Vector2<T> someValue)
		{
			return new Vector3<T>(someValue.X,someValue.Y,default(T));
		}

	}