예제 #1
0
		/// <summary>
		/// Tries to set a named property or field
		/// </summary>
		/// <param name="luaState"></param>
		/// <param name="targetType"></param>
		/// <param name="target"></param>
		/// <param name="bindingType"></param>
		/// <returns>false if unable to find the named member, true for success</returns>
		bool TrySetMember (LuaState luaState, ProxyType targetType, object target, BindingFlags bindingType, out string detailMessage)
		{
			detailMessage = null;   // No error yet

			// If not already a string just return - we don't want to call tostring - which has the side effect of 
			// changing the lua typecode to string
			// Note: We don't use isstring because the standard lua C isstring considers either strings or numbers to
			// be true for isstring.
			if (LuaLib.LuaType (luaState, 2) != LuaTypes.String) {
				detailMessage = "property names must be strings";
				return false;
			}

			// We only look up property names by string
			string fieldName = LuaLib.LuaToString (luaState, 2).ToString ();
			if (fieldName == null || fieldName.Length < 1 || !(char.IsLetter (fieldName [0]) || fieldName [0] == '_')) {
				detailMessage = "invalid property name";
				return false;
			}

			// Find our member via reflection or the cache
			var member = (MemberInfo)CheckMemberCache (memberCache, targetType, fieldName);
			if (member == null) {
				var members = targetType.GetMember (fieldName, bindingType | BindingFlags.Public);

				if (members.Length > 0) {
					member = members [0];
					SetMemberCache (memberCache, targetType, fieldName, member);
				} else {
					detailMessage = "field or property '" + fieldName + "' does not exist";
					return false;
				}
			}
#if NETFX_CORE
			if (member is FieldInfo) {
#else
			if (member.MemberType == MemberTypes.Field) {
#endif

				var field = (FieldInfo)member;
				object val = translator.GetAsType (luaState, 3, field.FieldType);

				try {
					field.SetValue (target, val);
				} catch (Exception e) {
					ThrowError (luaState, e);
				}

				// We did a call
				return true;
#if NETFX_CORE
			} else if (member is PropertyInfo) {
#else
			} else if (member.MemberType == MemberTypes.Property) {
#endif
				var property = (PropertyInfo)member;
				object val = translator.GetAsType (luaState, 3, property.PropertyType);

				try {
					property.SetValue (target, val, null);
				} catch (Exception e) {
					ThrowError (luaState, e);
				}

				// We did a call
				return true;
			}

			detailMessage = "'" + fieldName + "' is not a .net field or property";
			return false;
		}

		/*
		 * Writes to fields or properties, either static or instance. Throws an error
		 * if the operation is invalid.
		 */
		private int SetMember (LuaState luaState, ProxyType targetType, object target, BindingFlags bindingType)
		{
			string detail;
			bool success = TrySetMember (luaState, targetType, target, bindingType, out detail);

			if (!success)
				translator.ThrowError (luaState, detail);

			return 0;
		}

		/// <summary>
		/// Convert a C# exception into a Lua error
		/// </summary>
		/// <param name="e"></param>
		/// We try to look into the exception to give the most meaningful description
		void ThrowError (LuaState luaState, Exception e)
		{
			// If we got inside a reflection show what really happened
			var te = e as TargetInvocationException;

			if (te != null)
				e = te.InnerException;

			translator.ThrowError (luaState, e);
		}
예제 #2
0
		/// <summary>
		/// Does this method exist as either an instance or static?
		/// </summary>
		/// <param name="objType"></param>
		/// <param name="methodName"></param>
		/// <returns></returns>
		bool IsMemberPresent (ProxyType objType, string methodName)
		{
			object cachedMember = CheckMemberCache (memberCache, objType, methodName);

			if (cachedMember != null)
				return true;

			var members = objType.GetMember (methodName, BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public);
			return (members.Length > 0);
		}
예제 #3
0
		/*
		 * Pushes the value of a member or a delegate to call it, depending on the type of
		 * the member. Works with static or instance members.
		 * Uses reflection to find members, and stores the reflected MemberInfo object in
		 * a cache (indexed by the type of the object and the name of the member).
		 */
		int GetMember (LuaState luaState, ProxyType objType, object obj, string methodName, BindingFlags bindingType)
		{
			bool implicitStatic = false;
			MemberInfo member = null;
			object cachedMember = CheckMemberCache (memberCache, objType, methodName);

			if (cachedMember is LuaNativeFunction) {
				translator.PushFunction (luaState, (LuaNativeFunction)cachedMember);
				translator.Push (luaState, true);
				return 2;
			} else if (cachedMember != null)
				member = (MemberInfo)cachedMember;
			else {
				var members = objType.GetMember (methodName, bindingType | BindingFlags.Public);

				if (members.Length > 0)
					member = members [0];
				else {
					// If we can't find any suitable instance members, try to find them as statics - but we only want to allow implicit static
					members = objType.GetMember (methodName, bindingType | BindingFlags.Static | BindingFlags.Public);

					if (members.Length > 0) {
						member = members [0];
						implicitStatic = true;
					}
				}
			}

			if (member != null) {
#if NETFX_CORE
				if (member is FieldInfo) {
#else
				if (member.MemberType == MemberTypes.Field) {
#endif
					var field = (FieldInfo)member;

					if (cachedMember == null)
						SetMemberCache (memberCache, objType, methodName, member);

					try {
						var value = field.GetValue (obj);
						translator.Push (luaState, value);							
					} catch {
						LuaLib.LuaPushNil (luaState);
					}
#if NETFX_CORE
				} else if (member is PropertyInfo) {
#else
				} else if (member.MemberType == MemberTypes.Property) {
#endif
					var property = (PropertyInfo)member;
					if (cachedMember == null)
						SetMemberCache (memberCache, objType, methodName, member);

					try {
						object value = property.GetValue (obj, null);
						translator.Push (luaState, value);
							
					} catch (ArgumentException) {
						// If we can't find the getter in our class, recurse up to the base class and see
						// if they can help.
						if (objType.UnderlyingSystemType != typeof(object))
#if NETFX_CORE
							return GetMember (luaState, new ProxyType(objType.UnderlyingSystemType.GetTypeInfo().BaseType), obj, methodName, bindingType);
#else
							return GetMember (luaState, new ProxyType(objType.UnderlyingSystemType.BaseType), obj, methodName, bindingType);
#endif
						else
							LuaLib.LuaPushNil (luaState);
					} catch (TargetInvocationException e) {  // Convert this exception into a Lua error
						ThrowError (luaState, e);
						LuaLib.LuaPushNil (luaState);
					}
#if NETFX_CORE
				} else if (member is EventInfo) {
#else
				} else if (member.MemberType == MemberTypes.Event) {
#endif
					var eventInfo = (EventInfo)member;
					if (cachedMember == null)
						SetMemberCache (memberCache, objType, methodName, member);

					translator.Push (luaState, new RegisterEventHandler (translator.pendingEvents, obj, eventInfo));
				} else if (!implicitStatic) {
#if NETFX_CORE
					var typeInfo = member as TypeInfo;
					if (typeInfo != null && !typeInfo.IsPublic && !typeInfo.IsNotPublic) {
#else
					if (member.MemberType == MemberTypes.NestedType) {
#endif

						// kevinh - added support for finding nested types-
						// cache us
						if (cachedMember == null)
							SetMemberCache (memberCache, objType, methodName, member);

						// Find the name of our class
						string name = member.Name;
						var dectype = member.DeclaringType;

						// Build a new long name and try to find the type by name
						string longname = dectype.FullName + "+" + name;
						var nestedType = translator.FindType (longname);
						translator.PushType (luaState, nestedType);
					} else {
						// Member type must be 'method'
						var wrapper = new LuaNativeFunction ((new LuaMethodWrapper (translator, objType, methodName, bindingType)).invokeFunction);

						if (cachedMember == null)
							SetMemberCache (memberCache, objType, methodName, wrapper);

						translator.PushFunction (luaState, wrapper);
						translator.Push (luaState, true);
						return 2;
					}
				} else {
					// If we reach this point we found a static method, but can't use it in this context because the user passed in an instance
					translator.ThrowError (luaState, "can't pass instance to static method " + methodName);
					LuaLib.LuaPushNil (luaState);
				}
			} else {

				if (objType.UnderlyingSystemType != typeof(object)) {
					#if NETFX_CORE
					return GetMember (luaState, new ProxyType(objType.UnderlyingSystemType.GetTypeInfo().BaseType), obj, methodName, bindingType);
					#else
					return GetMember (luaState, new ProxyType(objType.UnderlyingSystemType.BaseType), obj, methodName, bindingType);
					#endif
				}
				// kevinh - we want to throw an exception because meerly returning 'nil' in this case
				// is not sufficient.  valid data members may return nil and therefore there must be some
				// way to know the member just doesn't exist.
				translator.ThrowError (luaState, "unknown member name " + methodName);
				LuaLib.LuaPushNil (luaState);
			}

			// push false because we are NOT returning a function (see luaIndexFunction)
			translator.Push (luaState, false);
			return 2;
		}
예제 #4
0
		/// <summary>
		/// Tries to set a named property or field
		/// </summary>
		/// <param name="luaState"></param>
		/// <param name="targetType"></param>
		/// <param name="target"></param>
		/// <param name="bindingType"></param>
		/// <returns>false if unable to find the named member, true for success</returns>
		bool TrySetMember (LuaState luaState, ProxyType targetType, object target, BindingFlags bindingType, out string detailMessage)
		{
			detailMessage = null;   // No error yet

			// If not already a string just return - we don't want to call tostring - which has the side effect of 
			// changing the lua typecode to string
			// Note: We don't use isstring because the standard lua C isstring considers either strings or numbers to
			// be true for isstring.
			if (LuaLib.LuaType (luaState, 2) != LuaTypes.String) {
				detailMessage = "property names must be strings";
				return false;
			}

			// We only look up property names by string
			string fieldName = LuaLib.LuaToString (luaState, 2).ToString ();
			if (fieldName == null || fieldName.Length < 1 || !(char.IsLetter (fieldName [0]) || fieldName [0] == '_')) {
				detailMessage = "invalid property name";
				return false;
			}

			// Find our member via reflection or the cache
			var member = (MemberInfo)CheckMemberCache (memberCache, targetType, fieldName);
			if (member == null) {
				var members = targetType.GetMember (fieldName, bindingType | BindingFlags.Public);

				if (members.Length > 0) {
					member = members [0];
					SetMemberCache (memberCache, targetType, fieldName, member);
				} else {
					detailMessage = "field or property '" + fieldName + "' does not exist";
					return false;
				}
			}

			if (member.MemberType == MemberTypes.Field) {
				var field = (FieldInfo)member;
				object val = translator.GetAsType (luaState, 3, field.FieldType);

				try {
					field.SetValue (target, val);
				} catch (Exception e) {
					ThrowError (luaState, e);
				}

				// We did a call
				return true;
			} else if (member.MemberType == MemberTypes.Property) {
				var property = (PropertyInfo)member;
				object val = translator.GetAsType (luaState, 3, property.PropertyType);

				try {
					property.SetValue (target, val, null);
				} catch (Exception e) {
					ThrowError (luaState, e);
				}

				// We did a call
				return true;
			}

			detailMessage = "'" + fieldName + "' is not a .net field or property";
			return false;
		}