{"record":{"id":"ec26c6b624c47f16","repo":"tui-cs/Terminal.Gui","slug":"cloning-of-collection-type-type-name-is-not-supp-ec26c6","errorCode":null,"errorMessage":"Cloning of collection type {type.Name} is not supported without a parameterless constructor.","messagePattern":"Cloning of collection type (.+?) is not supported without a parameterless constructor\\.","errorType":"exception","errorClass":"NotSupportedException","httpStatus":null,"severity":"error","filePath":"Terminal.Gui/Configuration/DeepCloner.cs","lineNumber":230,"sourceCode":"        // Check for immutable collections and throw if found\n        if (type.IsGenericType)\n        {\n            Type genericTypeDef = type.GetGenericTypeDefinition ();\n\n            if (genericTypeDef.FullName != null && genericTypeDef.FullName.StartsWith (\"System.Collections.Immutable\"))\n            {\n                throw new NotSupportedException ($\"Cloning of immutable collections like {type.Name} is not supported.\");\n            }\n        }\n\n        if (source is not IList)\n        {\n            throw new NotSupportedException ($\"Cloning of collection type {type.Name} is not supported unless it implements IList.\");\n        }\n\n        if (Activator.CreateInstance (type) is not IList tempList)\n        {\n            throw new NotSupportedException ($\"Cloning of collection type {type.Name} is not supported without a parameterless constructor.\");\n        }\n\n        // Add to visited before cloning contents to prevent circular reference issues\n        visited.TryAdd (source, tempList);\n\n        foreach (object? item in (IEnumerable)source)\n        {\n            object? clonedItem = DeepCloneInternal (item, visited);\n            tempList.Add (clonedItem);\n        }\n\n        return tempList;\n    }\n\n    #region Dictionary Support\n\n    [UnconditionalSuppressMessage (\"AOT\", \"IL3050\", Justification = \"Dictionary cloning constructs supported runtime dictionary shapes (Dictionary<,> and ConcurrentDictionary<,>) via MakeGenericType, which is validated by NativeAOT publish tests.\")]\n    [UnconditionalSuppressMessage (\"Trimming\", \"IL2075\", Justification = \"Dictionary cloning reads the runtime dictionary comparer from supported dictionary types to preserve comparer semantics.\")]","sourceCodeStart":212,"sourceCodeEnd":248,"githubUrl":"https://github.com/tui-cs/Terminal.Gui/blob/2e47b11478db083499917f2ad27c34d30efb0df1/Terminal.Gui/Configuration/DeepCloner.cs#L212-L248","documentation":"Thrown by DeepCloner.CloneCollection when an ICollection-implementing, IList-implementing collection type cannot be instantiated as an IList via Activator.CreateInstance(type). The cloner refuses to clone collections it cannot construct with a parameterless constructor, because it needs an empty destination list to copy cloned elements into. This is a hard guard at DeepCloner.cs:228-231.","triggerScenarios":"DeepClone is called on an object graph that transitively contains an ICollection whose runtime type (1) has no public parameterless constructor, or (2) returns a non-IList instance from Activator.CreateInstance (e.g. a Nullable<T>-boxed struct, or a collection whose default ctor yields a type not assignable to IList). In practice this most often surfaces under NativeAOT/trimming where Activator.CreateInstance returns null for trimmed constructors before this line, or for custom collection types with only parameterized constructors.","commonSituations":"A user stores a custom collection type (with only an int-capacity or IEqualityComparer constructor) inside a configuration scope property; ConfigurationManager applies the scope and triggers a deep clone. Also seen after upgrading to a Terminal.Gui version that deep-clones more aggressively, exposing a previously-uncloned custom collection.","solutions":["Replace the custom collection type with List<T> (which has a parameterless constructor) for any property that participates in a configuration scope.","Add a public parameterless constructor to the custom collection type so Activator.CreateInstance can build it.","Ensure the collection type implements IList (not just ICollection/IEnumerable); types implementing only ICollection and IEnumerable but not IList hit the earlier guard at line 223-226, not this one.","If running under NativeAOT, register the collection type in a JsonSerializerContext (SourceGenerationContext) so the AOT fallback path in CreateInstance/DeepCloneInternal can construct it.","Avoid storing immutable or frozen collections in clonable config; convert to List<T> before assigning to a ConfigProperty."],"exampleFix":"// before\npublic class MyScope\n{\n    public ReadOnlyCollection<int> Items { get; set; } // no parameterless ctor, not IList-creatable\n}\n\n// after\npublic class MyScope\n{\n    public List<int> Items { get; set; } = new ();\n}","handlingStrategy":"type-guard","validationCode":"// Before cloning, verify the collection type is IList-constructible\nstatic bool IsClonableCollection (object? obj)\n{\n    if (obj is not IList) return false;\n    Type t = obj.GetType ();\n    return t.GetConstructor (Type.EmptyTypes) != null\n        && typeof (IList).IsAssignableFrom (t);\n}\n\n// Usage\nif (!IsClonableCollection (myConfigProperty))\n{\n    myConfigProperty = new List<...> (...); // normalize to List<T>\n}","typeGuard":"static bool IsClonableCollection<T> (T value) where T : notnull\n{\n    Type t = value.GetType ();\n    return value is IList\n        && t.GetConstructor (Type.EmptyTypes) is not null\n        && !t.FullName!.StartsWith (\"System.Collections.Immutable\");\n}","tryCatchPattern":"try\n{\n    var clone = DeepCloner.DeepClone (configObject);\n}\ncatch (NotSupportedException ex) when (ex.Message.Contains (\"parameterless constructor\"))\n{\n    // Normalize the offending collection to List<T> and retry,\n    // or report which property holds the unsupported type.\n}","preventionTips":["Use List<T> for all collection-typed configuration properties.","Never store immutable/frozen collections in objects passed to DeepClone.","Add a unit test that DeepClones every configuration scope type to catch unsupported types early.","Under NativeAOT, register collection types in a JsonSerializerContext so the AOT fallback can construct them."],"tags":["deepcloner","collections","configuration","reflection","aot"],"backgroundTag":null,"analyzedSha":"2e47b11478db083499917f2ad27c34d30efb0df1","analyzedAt":"2026-08-13T19:20:08.826Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}