/// <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); }
/// <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); }
/* * 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; }
/// <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; }