Ensure LuaValues are disposed.
Adding in these missing calls prevents these instances from having to be finalized.
This commit is contained in:
@@ -64,7 +64,19 @@ namespace OpenRA.Scripting
|
||||
}
|
||||
}
|
||||
|
||||
// For global-level bindings
|
||||
/// <summary>
|
||||
/// Provides global bindings in Lua code.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Instance methods and properties declared in derived classes will be made available in Lua. Use
|
||||
/// <see cref="ScriptGlobalAttribute"/> on your derived class to specify the name exposed in Lua. It is recommended
|
||||
/// to apply <see cref="DescAttribute"/> against each method or property to provide a description of what it does.
|
||||
///
|
||||
/// Any parameters to your method that are <see cref="LuaValue"/>s will be disposed automatically when your method
|
||||
/// completes. If you need to return any of these values, or need them to live longer than your method, you must
|
||||
/// use <see cref="LuaValue.CopyReference"/> to get your own copy of the value. Any copied values you return will
|
||||
/// be disposed automatically, but you assume responsibility for disposing any other copies.
|
||||
/// </remarks>
|
||||
public abstract class ScriptGlobal : ScriptObjectWrapper
|
||||
{
|
||||
protected override string DuplicateKeyError(string memberName) { return "Table '{0}' defines multiple members '{1}'".F(Name, memberName); }
|
||||
@@ -78,11 +90,27 @@ namespace OpenRA.Scripting
|
||||
var type = this.GetType();
|
||||
var names = type.GetCustomAttributes<ScriptGlobalAttribute>(true);
|
||||
if (names.Length != 1)
|
||||
throw new InvalidOperationException("[LuaGlobal] attribute not found for global table '{0}'".F(type));
|
||||
throw new InvalidOperationException("[ScriptGlobal] attribute not found for global table '{0}'".F(type));
|
||||
|
||||
Name = names.First().Name;
|
||||
Bind(new[] { this });
|
||||
}
|
||||
|
||||
protected IEnumerable<T> FilteredObjects<T>(IEnumerable<T> objects, LuaFunction filter)
|
||||
{
|
||||
if (filter != null)
|
||||
{
|
||||
objects = objects.Where(a =>
|
||||
{
|
||||
using (var luaObject = a.ToLuaValue(Context))
|
||||
using (var filterResult = filter.Call(luaObject))
|
||||
using (var result = filterResult.First())
|
||||
return result.ToBoolean();
|
||||
});
|
||||
}
|
||||
|
||||
return objects;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class ScriptGlobalAttribute : Attribute
|
||||
|
||||
@@ -44,31 +44,54 @@ namespace OpenRA.Scripting
|
||||
|
||||
LuaValue Invoke(LuaVararg args)
|
||||
{
|
||||
if (!IsMethod)
|
||||
throw new LuaException("Trying to invoke a ScriptMemberWrapper that isn't a method!");
|
||||
|
||||
var mi = (MethodInfo)Member;
|
||||
var pi = mi.GetParameters();
|
||||
|
||||
var clrArgs = new object[pi.Length];
|
||||
var argCount = args.Count;
|
||||
for (var i = 0; i < pi.Length; i++)
|
||||
object[] clrArgs = null;
|
||||
try
|
||||
{
|
||||
if (i >= argCount)
|
||||
{
|
||||
if (!pi[i].IsOptional)
|
||||
throw new LuaException("Argument '{0}' of '{1}' is not optional.".F(pi[i].LuaDocString(), Member.LuaDocString()));
|
||||
if (!IsMethod)
|
||||
throw new LuaException("Trying to invoke a ScriptMemberWrapper that isn't a method!");
|
||||
|
||||
clrArgs[i] = pi[i].DefaultValue;
|
||||
continue;
|
||||
var mi = (MethodInfo)Member;
|
||||
var pi = mi.GetParameters();
|
||||
|
||||
clrArgs = new object[pi.Length];
|
||||
|
||||
var argCount = args.Count;
|
||||
for (var i = 0; i < pi.Length; i++)
|
||||
{
|
||||
if (i >= argCount)
|
||||
{
|
||||
if (!pi[i].IsOptional)
|
||||
throw new LuaException("Argument '{0}' of '{1}' is not optional.".F(pi[i].LuaDocString(), Member.LuaDocString()));
|
||||
|
||||
clrArgs[i] = pi[i].DefaultValue;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!args[i].TryGetClrValue(pi[i].ParameterType, out clrArgs[i]))
|
||||
throw new LuaException("Unable to convert parameter {0} to {1}".F(i, pi[i].ParameterType.Name));
|
||||
}
|
||||
|
||||
if (!args[i].TryGetClrValue(pi[i].ParameterType, out clrArgs[i]))
|
||||
throw new LuaException("Unable to convert parameter {0} to {1}".F(i, pi[i].ParameterType.Name));
|
||||
return mi.Invoke(Target, clrArgs).ToLuaValue(context);
|
||||
}
|
||||
finally
|
||||
{
|
||||
// Clean up all the Lua arguments that were given to us.
|
||||
foreach (var arg in args)
|
||||
arg.Dispose();
|
||||
args.Dispose();
|
||||
|
||||
var ret = mi.Invoke(Target, clrArgs);
|
||||
return ret.ToLuaValue(context);
|
||||
// If we created any arrays of LuaValues to pass around, we need to dispose those too.
|
||||
if (clrArgs != null)
|
||||
{
|
||||
foreach (var arg in clrArgs)
|
||||
{
|
||||
if (!(arg is LuaValue[]))
|
||||
continue;
|
||||
foreach (var value in (LuaValue[])arg)
|
||||
value.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public LuaValue Get(LuaRuntime runtime)
|
||||
@@ -77,10 +100,7 @@ namespace OpenRA.Scripting
|
||||
return runtime.CreateFunctionFromDelegate((Func<LuaVararg, LuaValue>)Invoke);
|
||||
|
||||
if (IsGetProperty)
|
||||
{
|
||||
var pi = Member as PropertyInfo;
|
||||
return pi.GetValue(Target, null).ToLuaValue(context);
|
||||
}
|
||||
return ((PropertyInfo)Member).GetValue(Target, null).ToLuaValue(context);
|
||||
|
||||
throw new LuaException("The property '{0}' is write-only".F(Member.Name));
|
||||
}
|
||||
@@ -89,7 +109,7 @@ namespace OpenRA.Scripting
|
||||
{
|
||||
if (IsSetProperty)
|
||||
{
|
||||
var pi = Member as PropertyInfo;
|
||||
var pi = (PropertyInfo)Member;
|
||||
object clrValue;
|
||||
if (!value.TryGetClrValue(pi.PropertyType, out clrValue))
|
||||
throw new LuaException("Unable to convert '{0}' to Clr type '{1}'".F(value.WrappedClrType().Name, pi.PropertyType));
|
||||
|
||||
@@ -107,13 +107,22 @@ namespace OpenRA.Scripting
|
||||
|
||||
foreach (var kv in table)
|
||||
{
|
||||
object element;
|
||||
if (innerType == typeof(LuaValue))
|
||||
element = kv.Value;
|
||||
else if (!kv.Value.TryGetClrValue(innerType, out element))
|
||||
throw new LuaException("Unable to convert table value of type {0} to type {1}".F(kv.Value.WrappedClrType(), innerType));
|
||||
using (kv.Key)
|
||||
{
|
||||
object element;
|
||||
if (innerType == typeof(LuaValue))
|
||||
element = kv.Value;
|
||||
else
|
||||
{
|
||||
var elementHasClrValue = kv.Value.TryGetClrValue(innerType, out element);
|
||||
if (!elementHasClrValue || !(element is LuaValue))
|
||||
kv.Value.Dispose();
|
||||
if (!elementHasClrValue)
|
||||
throw new LuaException("Unable to convert table value of type {0} to type {1}".F(kv.Value.WrappedClrType(), innerType));
|
||||
}
|
||||
|
||||
array.SetValue(element, i++);
|
||||
array.SetValue(element, i++);
|
||||
}
|
||||
}
|
||||
|
||||
clrObject = array;
|
||||
@@ -159,11 +168,13 @@ namespace OpenRA.Scripting
|
||||
|
||||
if (obj is Array)
|
||||
{
|
||||
var array = obj as Array;
|
||||
var array = (Array)obj;
|
||||
var i = 1;
|
||||
var table = context.CreateTable();
|
||||
|
||||
foreach (var x in array)
|
||||
table.Add(i++, x.ToLuaValue(context));
|
||||
using (LuaValue key = i++, value = x.ToLuaValue(context))
|
||||
table.Add(key, value);
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user