Skip to content

Commit d49d2b9

Browse files
committed
Refactor and enhance error handling in ListFunctions
- Added new using directives and removed duplicates in ConvertToDictionaryCmdlet.cs. - Improved KeyComparer condition and introduced nullable dictType for better type handling. - Enhanced error handling with ListFunctionsException to provide more context on failures. - Updated ValidateScriptVariableAttribute.cs to use HashSet<string> for better performance and null handling. - Introduced ObjectExtensions class in ObjectExtensions.cs for cloning functionality.
1 parent 4335109 commit d49d2b9

File tree

4 files changed

+86
-20
lines changed

4 files changed

+86
-20
lines changed

src/engine/ListFunctions-Next/Cmdlets/Constructs/ConvertToDictionaryCmdlet.cs

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using ListFunctions.Extensions;
1+
using ListFunctions.Exceptions;
2+
using ListFunctions.Extensions;
23
using ListFunctions.Modern;
34
using ListFunctions.Modern.Variables;
45
using ListFunctions.Validation;
@@ -119,29 +120,33 @@ private IDictionary CreateDictionary(object?[] inputObjects)
119120
_valueType = this.GetValueType(_valueType, inputObjects);
120121
}
121122

122-
if (this.KeyComparer is null && (_keyType.Equals(typeof(string))))
123+
if (this.KeyComparer is null && _keyType.Equals(typeof(string)))
123124
{
124125
this.KeyComparer = StringComparer.OrdinalIgnoreCase;
125126
}
126127

127128
object[] args = this.KeyComparer is null
128129
? Array.Empty<object>()
129130
: new object[] { this.KeyComparer };
130-
131+
132+
Type? dictType = null;
131133
try
132134
{
133-
Type dictType = typeof(Dictionary<,>).MakeGenericType(_keyType, _valueType);
135+
dictType = typeof(Dictionary<,>).MakeGenericType(_keyType, _valueType);
134136
return Activator.CreateInstance(dictType, args) as IDictionary
135137
?? throw new InvalidOperationException("Somehow, Dictionary is not an IDictionary?");
136138
}
137139
catch (Exception e)
138140
{
139-
var rec = e.ToRecord(ErrorCategory.InvalidOperation, new Dictionary<string, object?>(3, StringComparer.OrdinalIgnoreCase)
140-
{
141-
{ nameof(InputObject), inputObjects },
142-
{ "KeyType", _keyType },
143-
{ "ValueType", _valueType },
144-
});
141+
ListFunctionsException ex = new($"Failed to instantiate dictionary with the arguments supplied - {e.Message}", e);
142+
IDictionary data = ex.Data;
143+
data["KeyType"] = _keyType;
144+
data[nameof(InputObject)] = inputObjects.DeepClone();
145+
data[nameof(ValueType)] = _valueType;
146+
data["DictionaryType"] = dictType;
147+
148+
var rec = ex.ToRecord(ErrorCategory.InvalidOperation, targetObj: null);
149+
145150
this.ThrowTerminatingError(rec);
146151
throw;
147152
}

src/engine/ListFunctions-Next/Validation/ValidateScriptVariableAttribute.cs

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -121,8 +121,8 @@ private static bool IsAllValid(ScriptBlock block, HashSet<string>? mustContainNa
121121
: block.Ast.FindAll(searchNestedScriptBlocks: false, predicate: IsVariableAst);
122122

123123
return allowsArgs
124-
? IsValidWithIndexes(asts, mustContainNames, mustContainIndexes)
125-
: IsValidNoIndexes(asts, mustContainNames, mustContainIndexes);
124+
? IsValidWithIndexes(asts, mustContainNames, mustContainIndexes!)
125+
: IsValidNoIndexes(asts, mustContainNames!);
126126
}
127127

128128
private static bool IsVariableAst(Ast ast)
@@ -141,32 +141,30 @@ private static bool IsArgsIndexed(Ast ast)
141141
&& Args.Equals(varAst.VariablePath.UserPath, StringComparison.OrdinalIgnoreCase);
142142
}
143143

144-
private static bool IsValidWithIndexes(IEnumerable<Ast> asts, ICollection<string>? anyNames, HashSet<int>? orAnyIndexes)
144+
private static bool IsValidWithIndexes(IEnumerable<Ast> asts, HashSet<string>? anyNames, HashSet<int> orAnyIndexes)
145145
{
146-
if (anyNames is null) anyNames = Array.Empty<string>();
147-
146+
bool isNotNull = !(anyNames is null || anyNames.Count == 0);
148147
foreach (Ast ast in asts.AsValueEnumerable())
149148
{
150-
if (ast is VariableExpressionAst varAst && anyNames.Contains(varAst.VariablePath.UserPath))
149+
if (ast is VariableExpressionAst varAst && isNotNull && anyNames!.Contains(varAst.VariablePath.UserPath))
151150
{
152151
return true;
153152
}
154153
else if (ast is IndexExpressionAst indexAst && indexAst.Index is ConstantExpressionAst constAst && constAst.Value is int index
155154
&&
156-
orAnyIndexes!.Contains(index))
155+
orAnyIndexes.Contains(index))
157156
{
158157
return true;
159158
}
160159
}
161160

162161
return false;
163162
}
164-
private static bool IsValidNoIndexes(IEnumerable<Ast> asts, ICollection<string>? anyNames, HashSet<int>? _)
163+
private static bool IsValidNoIndexes(IEnumerable<Ast> asts, HashSet<string> anyNames)
165164
{
166-
Debug.Assert(!(anyNames is null), "Names should not null here.");
167165
foreach (VariableExpressionAst varAst in asts.AsValueEnumerable())
168166
{
169-
if (anyNames!.Contains(varAst.VariablePath.UserPath))
167+
if (anyNames.Contains(varAst.VariablePath.UserPath))
170168
{
171169
return true;
172170
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
5+
namespace ListFunctions.Exceptions
6+
{
7+
public class ListFunctionsException : Exception
8+
{
9+
public ListFunctionsException(string message, Exception? innerException)
10+
: base(message, innerException)
11+
{
12+
}
13+
}
14+
}
15+
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Diagnostics.CodeAnalysis;
4+
using System.Management.Automation;
5+
using System.Reflection;
6+
using System.Text;
7+
8+
#nullable enable
9+
10+
namespace ListFunctions.Extensions
11+
{
12+
public static class ObjectExtensions
13+
{
14+
[return: NotNullIfNotNull(nameof(obj))]
15+
internal static object? CloneIf(this object? obj)
16+
{
17+
if (obj is ICloneable cloneable)
18+
{
19+
return cloneable.Clone();
20+
}
21+
else if (obj is PSObject pso)
22+
{
23+
return pso.Copy();
24+
}
25+
else if (obj is PSCustomObject customObj)
26+
{
27+
return PSObject.AsPSObject(customObj).Copy();
28+
}
29+
else if (obj is PSMemberInfo member)
30+
{
31+
return member.Copy();
32+
}
33+
else
34+
{
35+
return obj;
36+
}
37+
}
38+
39+
public static object?[] DeepClone(this object?[]? source)
40+
{
41+
if (source is null || source.Length == 0)
42+
return Array.Empty<object>();
43+
44+
return Array.ConvertAll(source, CloneIf);
45+
}
46+
}
47+
}
48+

0 commit comments

Comments
 (0)