{"record":{"id":"b14ebde569fbd91b","repo":"stride3d/stride","slug":"expecting-a-type-inheriting-from-system-collections-generic","errorCode":null,"errorMessage":"Expecting a type inheriting from System.Collections.Generic.IDictionary<T,K>","messagePattern":"Expecting a type inheriting from System\\.Collections\\.Generic\\.IDictionary<T,K>","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"sources/core/Stride.Core.Reflection/TypeDescriptors/DictionaryDescriptor.cs","lineNumber":34,"sourceCode":"\n    Action<object, object, object?> addMethod;\n    Action<object, object> removeMethod;\n    Action<object, object, object?> setValueMethod;\n    Func<object, object, bool> containsKeyMethod;\n    Func<object, ICollection> getKeysMethod;\n    Func<object, ICollection> getValuesMethod;\n    Func<object, object, object?> getValueMethod;\n    Func<object, IEnumerable<KeyValuePair<object, object?>>> getEnumeratorMethod;\n    Action<object> clearMethod;\n\n    #pragma warning disable CS8618\n    // This warning is disabled because the necessary initialization will occur \n    // in the CreateDictionaryDelegates<T>() method, not in the constructor.\n    public DictionaryDescriptor(ITypeDescriptorFactory factory, Type type, bool emitDefaultValues, IMemberNamingConvention namingConvention)\n        : base(factory, type, emitDefaultValues, namingConvention)\n    {\n        if (!IsDictionary(type))\n            throw new ArgumentException(@\"Expecting a type inheriting from System.Collections.Generic.IDictionary<T,K>\", nameof(type));\n\n        // extract Key, Value types from IDictionary<??, ??>\n        var interfaceType = type.GetInterface(typeof(IDictionary<,>))!;\n        KeyType = interfaceType.GetGenericArguments()[0];\n        ValueType = interfaceType.GetGenericArguments()[1];\n        IsGenericDictionary = true;\n\n        // if the type has late bound generics, no delegates can be created as the type is invalid for calling collection operations\n        if (type.ContainsGenericParameters)\n            return;\n\n        var createMethod = typeof(DictionaryDescriptor).GetMethod(nameof(CreateDictionaryDelegates), BindingFlags.NonPublic | BindingFlags.Instance);\n        var genericCreateMethod = createMethod!.MakeGenericMethod([KeyType, ValueType]);\n        genericCreateMethod!.Invoke(this, []);\n    }\n    void CreateDictionaryDelegates<TKey, TValue>()\n    {\n        addMethod = (dictionary, key, value) => ((IDictionary<TKey, TValue?>)dictionary).Add((TKey)key, (TValue?)value);","sourceCodeStart":16,"sourceCodeEnd":52,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/core/Stride.Core.Reflection/TypeDescriptors/DictionaryDescriptor.cs#L16-L52","documentation":"DictionaryDescriptor requires the supplied type to implement the generic IDictionary<TKey,TValue> interface (checked by its IsDictionary helper). If the type is not a generic dictionary — e.g. a Hashtable, non-generic IDictionary, or a plain class — the constructor throws ArgumentException.","triggerScenarios":"new DictionaryDescriptor(factory, typeof(Hashtable), ...) or typeof(IDictionary) (non-generic) or any non-dictionary type; passing a custom collection that only implements IDictionary (non-generic).","commonSituations":"See trigger scenarios.","solutions":["Use System.Collections.Generic.Dictionary<TKey,TValue> or any type implementing IDictionary<TKey,TValue>.","Migrate non-generic IDictionary/Hashtable fields to generic dictionaries.","If you own the collection type, add IDictionary<TKey,TValue> to its interfaces.","Route truly non-dictionary types to the appropriate descriptor (ListDescriptor, ObjectDescriptor) via the factory."],"exampleFix":"// before\npublic Hashtable Settings;\n// after\npublic Dictionary<string, object> Settings;","handlingStrategy":"type-guard","validationCode":"if (!DictionaryDescriptor.IsDictionary(type))\n    throw new ArgumentException(\"Type must implement IDictionary<TKey,TValue>\", nameof(type));","typeGuard":"static bool IsGenericDictionary(Type t) => t.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IDictionary<,>));","tryCatchPattern":"try { var d = new DictionaryDescriptor(factory, type, true, naming); }\ncatch (ArgumentException ex) when (ex.Message.Contains(\"IDictionary\")) { /* use a generic dictionary type */ }","preventionTips":["Use Dictionary<TKey,TValue> (or implement IDictionary<TKey,TValue>) in serialized models.","Replace Hashtable/non-generic IDictionary fields during migration to Stride serialization."],"tags":["type-mismatch","dictionary","generics"],"backgroundTag":"type-mismatch","analyzedSha":"96fad776d210c221682aac1ccdf4c79dc046fc38","analyzedAt":"2026-09-14T02:59:31.279Z","contentChangedAt":"2026-09-14T02:59:31.279Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}