diff --git a/AmalgamationTool/DynamORM.Amalgamation.cs b/AmalgamationTool/DynamORM.Amalgamation.cs index f29fdc7..8bd0c6b 100644 --- a/AmalgamationTool/DynamORM.Amalgamation.cs +++ b/AmalgamationTool/DynamORM.Amalgamation.cs @@ -1341,10 +1341,13 @@ namespace DynamORM IsDisposed = true; - _command.Parameters.Clear(); + if (_command != null) + { + _command.Parameters.Clear(); - _command.Dispose(); - _command = null; + _command.Dispose(); + _command = null; + } } } @@ -4263,25 +4266,32 @@ namespace DynamORM /// Returns dumped instance. public static IDbCommand Dump(this IDbCommand command, TextWriter writer) { - writer.WriteLine("Type: {0}; Timeout: {1}; Query: {2}", command.CommandType, command.CommandTimeout, command.CommandText); - - if (command.Parameters.Count > 0) + try { - writer.WriteLine("Parameters:"); + writer.WriteLine("Type: {0}; Timeout: {1}; Query: {2}", command.CommandType, command.CommandTimeout, command.CommandText); - foreach (IDbDataParameter param in command.Parameters) + if (command.Parameters.Count > 0) { - writer.WriteLine(" '{0}' ({1} (s:{2} p:{3} s:{4})) = '{5}' ({6});", - param.ParameterName, - param.DbType, - param.Scale, - param.Precision, - param.Scale, - param.Value is byte[] ? ConvertByteArrayToHexString((byte[])param.Value) : param.Value ?? "NULL", - param.Value != null ? param.Value.GetType().Name : "DBNull"); - } + writer.WriteLine("Parameters:"); - writer.WriteLine(); + foreach (IDbDataParameter param in command.Parameters) + { + writer.WriteLine(" '{0}' ({1} (s:{2} p:{3} s:{4})) = '{5}' ({6});", + param.ParameterName, + param.DbType, + param.Scale, + param.Precision, + param.Scale, + param.Value is byte[] ? ConvertByteArrayToHexString((byte[])param.Value) : param.Value ?? "NULL", + param.Value != null ? param.Value.GetType().Name : "DBNull"); + } + + writer.WriteLine(); + } + } + catch (NullReferenceException) + { + writer.WriteLine("Command disposed."); } return command; @@ -4861,7 +4871,7 @@ namespace DynamORM { TValue val; - if (key != null && dict.TryGetValue(key, out val)) + if (key != null && dict != null && dict.TryGetValue(key, out val)) return val; return default(TValue); @@ -5655,8 +5665,8 @@ namespace DynamORM { TableName = mapper.Table == null || string.IsNullOrEmpty(mapper.Table.Name) ? type.Name : mapper.Table.Name; - OwnerName = mapper.Table == null || string.IsNullOrEmpty(mapper.Table.Name) ? - type.Name : mapper.Table.Name; + OwnerName = mapper.Table == null || string.IsNullOrEmpty(mapper.Table.Owner) ? + null : mapper.Table.Owner; } BuildAndCacheSchema(keys); @@ -8208,9 +8218,11 @@ namespace DynamORM if (node is Delegate) { using (DynamicParser p = DynamicParser.Parse((Delegate)node)) + { node = p.Result; - return Parse(node, ref columnSchema, pars, rawstr, decorate: decorate); // Intercept containers as in (x => "string") + return Parse(node, ref columnSchema, pars, rawstr, decorate: decorate); // Intercept containers as in (x => "string") + } } return Dispatch(node, ref columnSchema, pars, decorate, isMultiPart); @@ -9716,6 +9728,7 @@ namespace DynamORM index++; if (f == null) throw new ArgumentNullException(string.Format("Specification #{0} cannot be null.", index)); + using (DynamicParser parser = DynamicParser.Parse(f)) { object result = parser.Result; @@ -10295,39 +10308,41 @@ namespace DynamORM object result = null; using (DynamicParser p = DynamicParser.Parse(f)) + { result = p.Result; - if (result == null) - throw new ArgumentException(string.Format("Specification #{0} resolves to null.", index)); + if (result == null) + throw new ArgumentException(string.Format("Specification #{0} resolves to null.", index)); - string main = null; - string value = null; - string str = null; + string main = null; + string value = null; + string str = null; - // When 'x => x.Table.Column = value' or 'x => x.Column = value'... - if (result is DynamicParser.Node.SetMember) - { - DynamicParser.Node.SetMember node = (DynamicParser.Node.SetMember)result; + // When 'x => x.Table.Column = value' or 'x => x.Column = value'... + if (result is DynamicParser.Node.SetMember) + { + DynamicParser.Node.SetMember node = (DynamicParser.Node.SetMember)result; - DynamicSchemaColumn? col = GetColumnFromSchema(node.Name); - main = Database.DecorateName(node.Name); - value = Parse(node.Value, ref col, pars: Parameters, nulls: true); + DynamicSchemaColumn? col = GetColumnFromSchema(node.Name); + main = Database.DecorateName(node.Name); + value = Parse(node.Value, ref col, pars: Parameters, nulls: true); - str = string.Format("{0} = {1}", main, value); - _columns = _columns == null ? str : string.Format("{0}, {1}", _columns, str); - continue; + str = string.Format("{0} = {1}", main, value); + _columns = _columns == null ? str : string.Format("{0}, {1}", _columns, str); + continue; + } + else if (!(result is DynamicParser.Node) && !result.GetType().IsValueType) + { + Values(result); + continue; + } + + // Other specifications are considered invalid... + string err = string.Format("Specification '{0}' is invalid.", result); + str = Parse(result); + if (str.Contains("=")) err += " May have you used a '==' instead of a '=' operator?"; + throw new ArgumentException(err); } - else if (!(result is DynamicParser.Node) && !result.GetType().IsValueType) - { - Values(result); - continue; - } - - // Other specifications are considered invalid... - string err = string.Format("Specification '{0}' is invalid.", result); - str = Parse(result); - if (str.Contains("=")) err += " May have you used a '==' instead of a '=' operator?"; - throw new ArgumentException(err); } return this; @@ -11428,6 +11443,37 @@ namespace DynamORM return "{DynamicParser::Node::SetMember::Disposed}"; return string.Format("({0}.{1} = {2})", Host.Sketch(), Name.Sketch(), Value.Sketch()); } + + /// Performs application-defined tasks associated with + /// freeing, releasing, or resetting unmanaged resources. + /// If set to true dispose object. + public override void Dispose(bool disposing) + { + if (disposing) + { + try + { + if (Value != null) + { + var node = Value as Node; + if (node != null) + { + if (node.IsNodeAncestor(this)) + node.Host = null; + + node.Dispose(disposing); + } + + Value = null; + } + } + catch + { + } + } + + base.Dispose(disposing); + } } #endregion SetMember @@ -11508,6 +11554,42 @@ namespace DynamORM return string.Format("{0}{1}", Host.Sketch(), Indexes == null ? "[empty]" : Indexes.Sketch()); } + + /// Performs application-defined tasks associated with + /// freeing, releasing, or resetting unmanaged resources. + /// If set to true dispose object. + public override void Dispose(bool disposing) + { + if (disposing) + { + try + { + if (Indexes != null) + { + for (int i = 0; i < Indexes.Length; i++) + { + var node = Indexes[i] as Node; + if (node != null) + { + if (node.IsNodeAncestor(this)) + node.Host = null; + + node.Dispose(disposing); + } + } + + Array.Clear(Indexes, 0, Indexes.Length); + } + } + catch + { + } + + Indexes = null; + } + + base.Dispose(disposing); + } } #endregion GetIndex @@ -11572,6 +11654,37 @@ namespace DynamORM return string.Format("({0}{1} = {2})", Host.Sketch(), Indexes == null ? "[empty]" : Indexes.Sketch(), Value.Sketch()); } + + /// Performs application-defined tasks associated with + /// freeing, releasing, or resetting unmanaged resources. + /// If set to true dispose object. + public override void Dispose(bool disposing) + { + if (disposing) + { + try + { + if (Value != null) + { + var node = Value as Node; + if (node != null) + { + if (node.IsNodeAncestor(this)) + node.Host = null; + + node.Dispose(disposing); + } + + Value = null; + } + } + catch + { + } + } + + base.Dispose(disposing); + } } #endregion SetIndex @@ -11636,6 +11749,42 @@ namespace DynamORM base.GetObjectData(info, context); } + /// Performs application-defined tasks associated with + /// freeing, releasing, or resetting unmanaged resources. + /// If set to true dispose object. + public override void Dispose(bool disposing) + { + if (disposing) + { + try + { + if (Arguments != null) + { + for (int i = 0; i < Arguments.Length; i++) + { + var node = Arguments[i] as Node; + if (node != null) + { + if (node.IsNodeAncestor(this)) + node.Host = null; + + node.Dispose(disposing); + } + } + + Array.Clear(Arguments, 0, Arguments.Length); + } + } + catch + { + } + + Arguments = null; + } + + base.Dispose(disposing); + } + /// Returns a that represents this instance. /// A that represents this instance. public override string ToString() @@ -11719,6 +11868,42 @@ namespace DynamORM return string.Format("{0}.{1}{2}", Host.Sketch(), Name.Sketch(), Arguments == null ? "()" : Arguments.Sketch(brackets: "()".ToCharArray())); } + + /// Performs application-defined tasks associated with + /// freeing, releasing, or resetting unmanaged resources. + /// If set to true dispose object. + public override void Dispose(bool disposing) + { + if (disposing) + { + try + { + if (Arguments != null) + { + for (int i = 0; i < Arguments.Length; i++) + { + var node = Arguments[i] as Node; + if (node != null) + { + if (node.IsNodeAncestor(this)) + node.Host = null; + + node.Dispose(disposing); + } + } + + Array.Clear(Arguments, 0, Arguments.Length); + } + } + catch + { + } + + Arguments = null; + } + + base.Dispose(disposing); + } } #endregion Method @@ -11802,14 +11987,31 @@ namespace DynamORM { base.Dispose(disposing); - if (disposing && Right != null && Right is Node) + if (disposing) { - Node n = (Node)Right; + if (Left != null) + { + if (Left is Node) + { + Node n = (Node)Left; - if (!n.IsDisposed) - n.Dispose(disposing); + if (!n.IsDisposed) + n.Dispose(disposing); + } + } - Right = null; + if (Right != null) + { + if (Right is Node) + { + Node n = (Node)Right; + + if (!n.IsDisposed) + n.Dispose(disposing); + } + + Right = null; + } } } } @@ -11829,7 +12031,7 @@ namespace DynamORM public ExpressionType Operation { get; private set; } /// Gets host of the . - public Node Target { get { return Host; } } + public Node Target { get; private set; } /// /// Initializes a new instance of the class. @@ -11840,6 +12042,7 @@ namespace DynamORM : base(target) { Operation = operation; + Target = target; } /// @@ -11874,6 +12077,37 @@ namespace DynamORM return string.Format("({0} {1})", Operation, Host.Sketch()); } + + /// Performs application-defined tasks associated with + /// freeing, releasing, or resetting unmanaged resources. + /// If set to true dispose object. + public override void Dispose(bool disposing) + { + if (disposing) + { + try + { + if (Target != null) + { + var node = Target as Node; + if (node != null) + { + if (node.IsNodeAncestor(this)) + node.Host = null; + + node.Dispose(disposing); + } + + Target = null; + } + } + catch + { + } + } + + base.Dispose(disposing); + } } #endregion Unary @@ -12005,6 +12239,27 @@ namespace DynamORM Host = type == "NULL" ? null : (Node)info.GetValue("HostItem", Type.GetType(type)); } + /// Returns whether the given node is an ancestor of this instance. + /// The node to test. + /// True if the given node is an ancestor of this instance. + public bool IsNodeAncestor(Node node) + { + if (node != null) + { + Node parent = Host; + + while (parent != null) + { + if (object.ReferenceEquals(parent, node)) + return true; + + parent = parent.Host; + } + } + + return false; + } + /// Returns a that represents this instance. /// A that represents this instance. public override string ToString() @@ -12220,15 +12475,19 @@ namespace DynamORM { IsDisposed = true; - if (_uncertainResult != null && _uncertainResult is Node) + if (_uncertainResult != null) { - ((Node)_uncertainResult).Dispose(); + if (_uncertainResult is Node) + ((Node)_uncertainResult).Dispose(); + _uncertainResult = null; } - if (Last != null && !Last.IsDisposed) + if (Last != null) { - Last.Dispose(); + if (!Last.IsDisposed) + Last.Dispose(); + Last = null; } diff --git a/DynamORM.Tests/DynamORM.Tests.csproj b/DynamORM.Tests/DynamORM.Tests.csproj index 384ca3d..7ebb425 100644 --- a/DynamORM.Tests/DynamORM.Tests.csproj +++ b/DynamORM.Tests/DynamORM.Tests.csproj @@ -99,7 +99,6 @@ - diff --git a/DynamORM/Builders/Implementation/DynamicQueryBuilder.cs b/DynamORM/Builders/Implementation/DynamicQueryBuilder.cs index 9372834..d1d04b8 100644 --- a/DynamORM/Builders/Implementation/DynamicQueryBuilder.cs +++ b/DynamORM/Builders/Implementation/DynamicQueryBuilder.cs @@ -398,9 +398,11 @@ namespace DynamORM.Builders.Implementation if (node is Delegate) { using (DynamicParser p = DynamicParser.Parse((Delegate)node)) + { node = p.Result; - return Parse(node, ref columnSchema, pars, rawstr, decorate: decorate); // Intercept containers as in (x => "string") + return Parse(node, ref columnSchema, pars, rawstr, decorate: decorate); // Intercept containers as in (x => "string") + } } return Dispatch(node, ref columnSchema, pars, decorate, isMultiPart); diff --git a/DynamORM/Builders/Implementation/DynamicSelectQueryBuilder.cs b/DynamORM/Builders/Implementation/DynamicSelectQueryBuilder.cs index 8b7072f..012a0fb 100644 --- a/DynamORM/Builders/Implementation/DynamicSelectQueryBuilder.cs +++ b/DynamORM/Builders/Implementation/DynamicSelectQueryBuilder.cs @@ -974,6 +974,7 @@ namespace DynamORM.Builders.Implementation index++; if (f == null) throw new ArgumentNullException(string.Format("Specification #{0} cannot be null.", index)); + using (DynamicParser parser = DynamicParser.Parse(f)) { object result = parser.Result; diff --git a/DynamORM/Builders/Implementation/DynamicUpdateQueryBuilder.cs b/DynamORM/Builders/Implementation/DynamicUpdateQueryBuilder.cs index a6b049c..074b3ff 100644 --- a/DynamORM/Builders/Implementation/DynamicUpdateQueryBuilder.cs +++ b/DynamORM/Builders/Implementation/DynamicUpdateQueryBuilder.cs @@ -170,39 +170,41 @@ namespace DynamORM.Builders.Implementation object result = null; using (DynamicParser p = DynamicParser.Parse(f)) + { result = p.Result; - if (result == null) - throw new ArgumentException(string.Format("Specification #{0} resolves to null.", index)); + if (result == null) + throw new ArgumentException(string.Format("Specification #{0} resolves to null.", index)); - string main = null; - string value = null; - string str = null; + string main = null; + string value = null; + string str = null; - // When 'x => x.Table.Column = value' or 'x => x.Column = value'... - if (result is DynamicParser.Node.SetMember) - { - DynamicParser.Node.SetMember node = (DynamicParser.Node.SetMember)result; + // When 'x => x.Table.Column = value' or 'x => x.Column = value'... + if (result is DynamicParser.Node.SetMember) + { + DynamicParser.Node.SetMember node = (DynamicParser.Node.SetMember)result; - DynamicSchemaColumn? col = GetColumnFromSchema(node.Name); - main = Database.DecorateName(node.Name); - value = Parse(node.Value, ref col, pars: Parameters, nulls: true); + DynamicSchemaColumn? col = GetColumnFromSchema(node.Name); + main = Database.DecorateName(node.Name); + value = Parse(node.Value, ref col, pars: Parameters, nulls: true); - str = string.Format("{0} = {1}", main, value); - _columns = _columns == null ? str : string.Format("{0}, {1}", _columns, str); - continue; + str = string.Format("{0} = {1}", main, value); + _columns = _columns == null ? str : string.Format("{0}, {1}", _columns, str); + continue; + } + else if (!(result is DynamicParser.Node) && !result.GetType().IsValueType) + { + Values(result); + continue; + } + + // Other specifications are considered invalid... + string err = string.Format("Specification '{0}' is invalid.", result); + str = Parse(result); + if (str.Contains("=")) err += " May have you used a '==' instead of a '=' operator?"; + throw new ArgumentException(err); } - else if (!(result is DynamicParser.Node) && !result.GetType().IsValueType) - { - Values(result); - continue; - } - - // Other specifications are considered invalid... - string err = string.Format("Specification '{0}' is invalid.", result); - str = Parse(result); - if (str.Contains("=")) err += " May have you used a '==' instead of a '=' operator?"; - throw new ArgumentException(err); } return this; diff --git a/DynamORM/DynamicCommand.cs b/DynamORM/DynamicCommand.cs index 08816ee..e71b8a7 100644 --- a/DynamORM/DynamicCommand.cs +++ b/DynamORM/DynamicCommand.cs @@ -276,10 +276,13 @@ namespace DynamORM IsDisposed = true; - _command.Parameters.Clear(); + if (_command != null) + { + _command.Parameters.Clear(); - _command.Dispose(); - _command = null; + _command.Dispose(); + _command = null; + } } } diff --git a/DynamORM/DynamicExtensions.cs b/DynamORM/DynamicExtensions.cs index 5f345ce..170e125 100644 --- a/DynamORM/DynamicExtensions.cs +++ b/DynamORM/DynamicExtensions.cs @@ -805,25 +805,32 @@ namespace DynamORM /// Returns dumped instance. public static IDbCommand Dump(this IDbCommand command, TextWriter writer) { - writer.WriteLine("Type: {0}; Timeout: {1}; Query: {2}", command.CommandType, command.CommandTimeout, command.CommandText); - - if (command.Parameters.Count > 0) + try { - writer.WriteLine("Parameters:"); + writer.WriteLine("Type: {0}; Timeout: {1}; Query: {2}", command.CommandType, command.CommandTimeout, command.CommandText); - foreach (IDbDataParameter param in command.Parameters) + if (command.Parameters.Count > 0) { - writer.WriteLine(" '{0}' ({1} (s:{2} p:{3} s:{4})) = '{5}' ({6});", - param.ParameterName, - param.DbType, - param.Scale, - param.Precision, - param.Scale, - param.Value is byte[] ? ConvertByteArrayToHexString((byte[])param.Value) : param.Value ?? "NULL", - param.Value != null ? param.Value.GetType().Name : "DBNull"); - } + writer.WriteLine("Parameters:"); - writer.WriteLine(); + foreach (IDbDataParameter param in command.Parameters) + { + writer.WriteLine(" '{0}' ({1} (s:{2} p:{3} s:{4})) = '{5}' ({6});", + param.ParameterName, + param.DbType, + param.Scale, + param.Precision, + param.Scale, + param.Value is byte[] ? ConvertByteArrayToHexString((byte[])param.Value) : param.Value ?? "NULL", + param.Value != null ? param.Value.GetType().Name : "DBNull"); + } + + writer.WriteLine(); + } + } + catch (NullReferenceException) + { + writer.WriteLine("Command disposed."); } return command; @@ -1403,7 +1410,7 @@ namespace DynamORM { TValue val; - if (key != null && dict.TryGetValue(key, out val)) + if (key != null && dict != null && dict.TryGetValue(key, out val)) return val; return default(TValue); diff --git a/DynamORM/DynamicTable.cs b/DynamORM/DynamicTable.cs index 3c9ade7..2ddc673 100644 --- a/DynamORM/DynamicTable.cs +++ b/DynamORM/DynamicTable.cs @@ -273,8 +273,8 @@ namespace DynamORM { TableName = mapper.Table == null || string.IsNullOrEmpty(mapper.Table.Name) ? type.Name : mapper.Table.Name; - OwnerName = mapper.Table == null || string.IsNullOrEmpty(mapper.Table.Name) ? - type.Name : mapper.Table.Name; + OwnerName = mapper.Table == null || string.IsNullOrEmpty(mapper.Table.Owner) ? + null : mapper.Table.Owner; } BuildAndCacheSchema(keys); diff --git a/DynamORM/Helpers/Dynamics/DynamicParser.cs b/DynamORM/Helpers/Dynamics/DynamicParser.cs index e316004..36f3255 100644 --- a/DynamORM/Helpers/Dynamics/DynamicParser.cs +++ b/DynamORM/Helpers/Dynamics/DynamicParser.cs @@ -411,6 +411,38 @@ namespace DynamORM.Helpers.Dynamics return "{DynamicParser::Node::SetMember::Disposed}"; return string.Format("({0}.{1} = {2})", Host.Sketch(), Name.Sketch(), Value.Sketch()); } + + /// Performs application-defined tasks associated with + /// freeing, releasing, or resetting unmanaged resources. + /// If set to true dispose object. + public override void Dispose(bool disposing) + { + if (disposing) + { + try + { + if (Value != null) + { + var node = Value as Node; + if (node != null) + { + if (node.IsNodeAncestor(this)) + node.Host = null; + + node.Dispose(disposing); + } + + Value = null; + } + } + catch + { + } + + } + + base.Dispose(disposing); + } } #endregion SetMember @@ -491,6 +523,42 @@ namespace DynamORM.Helpers.Dynamics return string.Format("{0}{1}", Host.Sketch(), Indexes == null ? "[empty]" : Indexes.Sketch()); } + + /// Performs application-defined tasks associated with + /// freeing, releasing, or resetting unmanaged resources. + /// If set to true dispose object. + public override void Dispose(bool disposing) + { + if (disposing) + { + try + { + if (Indexes != null) + { + for (int i = 0; i < Indexes.Length; i++) + { + var node = Indexes[i] as Node; + if (node != null) + { + if (node.IsNodeAncestor(this)) + node.Host = null; + + node.Dispose(disposing); + } + } + + Array.Clear(Indexes, 0, Indexes.Length); + } + } + catch + { + } + + Indexes = null; + } + + base.Dispose(disposing); + } } #endregion GetIndex @@ -555,6 +623,38 @@ namespace DynamORM.Helpers.Dynamics return string.Format("({0}{1} = {2})", Host.Sketch(), Indexes == null ? "[empty]" : Indexes.Sketch(), Value.Sketch()); } + + /// Performs application-defined tasks associated with + /// freeing, releasing, or resetting unmanaged resources. + /// If set to true dispose object. + public override void Dispose(bool disposing) + { + if (disposing) + { + try + { + if (Value != null) + { + var node = Value as Node; + if (node != null) + { + if (node.IsNodeAncestor(this)) + node.Host = null; + + node.Dispose(disposing); + } + + Value = null; + } + } + catch + { + } + + } + + base.Dispose(disposing); + } } #endregion SetIndex @@ -619,6 +719,42 @@ namespace DynamORM.Helpers.Dynamics base.GetObjectData(info, context); } + /// Performs application-defined tasks associated with + /// freeing, releasing, or resetting unmanaged resources. + /// If set to true dispose object. + public override void Dispose(bool disposing) + { + if (disposing) + { + try + { + if (Arguments != null) + { + for (int i = 0; i < Arguments.Length; i++) + { + var node = Arguments[i] as Node; + if (node != null) + { + if (node.IsNodeAncestor(this)) + node.Host = null; + + node.Dispose(disposing); + } + } + + Array.Clear(Arguments, 0, Arguments.Length); + } + } + catch + { + } + + Arguments = null; + } + + base.Dispose(disposing); + } + /// Returns a that represents this instance. /// A that represents this instance. public override string ToString() @@ -702,6 +838,44 @@ namespace DynamORM.Helpers.Dynamics return string.Format("{0}.{1}{2}", Host.Sketch(), Name.Sketch(), Arguments == null ? "()" : Arguments.Sketch(brackets: "()".ToCharArray())); } + + + /// Performs application-defined tasks associated with + /// freeing, releasing, or resetting unmanaged resources. + /// If set to true dispose object. + public override void Dispose(bool disposing) + { + if (disposing) + { + try + { + if (Arguments != null) + { + for (int i = 0; i < Arguments.Length; i++) + { + var node = Arguments[i] as Node; + if (node != null) + { + if (node.IsNodeAncestor(this)) + node.Host = null; + + node.Dispose(disposing); + } + } + + Array.Clear(Arguments, 0, Arguments.Length); + } + } + catch + { + } + + Arguments = null; + } + + base.Dispose(disposing); + } + } #endregion Method @@ -785,14 +959,31 @@ namespace DynamORM.Helpers.Dynamics { base.Dispose(disposing); - if (disposing && Right != null && Right is Node) + if (disposing) { - Node n = (Node)Right; + if (Left != null) + { + if (Left is Node) + { + Node n = (Node)Left; - if (!n.IsDisposed) - n.Dispose(disposing); + if (!n.IsDisposed) + n.Dispose(disposing); + } + } - Right = null; + if (Right != null) + { + if (Right is Node) + { + Node n = (Node)Right; + + if (!n.IsDisposed) + n.Dispose(disposing); + } + + Right = null; + } } } } @@ -812,7 +1003,7 @@ namespace DynamORM.Helpers.Dynamics public ExpressionType Operation { get; private set; } /// Gets host of the . - public Node Target { get { return Host; } } + public Node Target { get; private set; } /// /// Initializes a new instance of the class. @@ -823,6 +1014,7 @@ namespace DynamORM.Helpers.Dynamics : base(target) { Operation = operation; + Target = target; } /// @@ -857,6 +1049,37 @@ namespace DynamORM.Helpers.Dynamics return string.Format("({0} {1})", Operation, Host.Sketch()); } + + /// Performs application-defined tasks associated with + /// freeing, releasing, or resetting unmanaged resources. + /// If set to true dispose object. + public override void Dispose(bool disposing) + { + if (disposing) + { + try + { + if (Target != null) + { + var node = Target as Node; + if (node != null) + { + if (node.IsNodeAncestor(this)) + node.Host = null; + + node.Dispose(disposing); + } + + Target = null; + } + } + catch + { + } + } + + base.Dispose(disposing); + } } #endregion Unary @@ -988,6 +1211,27 @@ namespace DynamORM.Helpers.Dynamics Host = type == "NULL" ? null : (Node)info.GetValue("HostItem", Type.GetType(type)); } + /// Returns whether the given node is an ancestor of this instance. + /// The node to test. + /// True if the given node is an ancestor of this instance. + public bool IsNodeAncestor(Node node) + { + if (node != null) + { + Node parent = Host; + + while (parent != null) + { + if (object.ReferenceEquals(parent, node)) + return true; + + parent = parent.Host; + } + } + + return false; + } + /// Returns a that represents this instance. /// A that represents this instance. public override string ToString() @@ -1148,7 +1392,15 @@ namespace DynamORM.Helpers.Dynamics throw new ArgumentException(string.Format("Argument '{0}' must be dynamic.", p.Name)); } - _uncertainResult = f.DynamicInvoke(_arguments.ToArray()); + try + { + _uncertainResult = f.DynamicInvoke(_arguments.ToArray()); + } + catch (TargetInvocationException e) + { + if (e.InnerException != null) throw e.InnerException; + else throw e; + } } /// @@ -1203,15 +1455,19 @@ namespace DynamORM.Helpers.Dynamics { IsDisposed = true; - if (_uncertainResult != null && _uncertainResult is Node) + if (_uncertainResult != null) { - ((Node)_uncertainResult).Dispose(); + if (_uncertainResult is Node) + ((Node)_uncertainResult).Dispose(); + _uncertainResult = null; } - if (Last != null && !Last.IsDisposed) + if (Last != null) { - Last.Dispose(); + if (!Last.IsDisposed) + Last.Dispose(); + Last = null; }