stride3d/stride · error · ArgumentException
Expecting a type inheriting from System.Collections.ISet
Error message
Expecting a type inheriting from System.Collections.ISet<T>
What it means
SetDescriptor requires its type parameter to implement System.Collections.Generic.ISet<T>; if IsSet(type) fails it throws ArgumentException 'Expecting a type inheriting from System.Collections.ISet<T>' with nameof(type) as the parameter name. Set descriptors rely on ISet<T>'s Add/Remove semantics to build edit delegates.
Solutions
- Ensure the type implements ISet<T> (HashSet<T>, SortedSet<T>, or a custom ISet<T>).
- Use ListDescriptor/OldCollectionDescriptor instead for list-like types.
- Fix the factory dispatch so only ISet<T>-implementing types reach SetDescriptor.
Example fix
// before var d = new SetDescriptor(factory, typeof(List<int>), false, convention); // after var d = new SetDescriptor(factory, typeof(HashSet<int>), false, convention);
Defensive patterns
Strategy: validation
Validate before calling
bool isSet = type.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(ISet<>));
if (!isSet) throw new InvalidOperationException($"{type} does not implement ISet<T>; use a list descriptor"); Type guard
static bool IsSetType(Type t) => t.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(ISet<>));
Try / catch
try { return new SetDescriptor(factory, type, emit, conv); }
catch (ArgumentException ex) when (ex.Message.Contains("ISet")) { return new ListDescriptor(factory, type, emit, conv); } Prevention
- Use HashSet<T> or SortedSet<T> for set-serialized properties.
- Verify ISet<T> implementation before registering a type with SetDescriptor.
- Keep custom set-like classes implementing ISet<T>, not just ICollection<T>.
When it happens
Trigger: Constructing SetDescriptor for a type that is not an ISet<T> — e.g. List<T>, IEnumerable<T>, or a custom collection without ISet<T> — directly or via a factory dispatch bug.
Common situations: Confusing HashSet<T>-backed properties with List<T> during descriptor registration; custom 'set-like' classes implementing ICollection<T> but not ISet<T>; serializer config mapping a collection property to the wrong descriptor kind.
Related errors
- Type [ ] is not supported as a modifiable collection
- The type of collection does not have a parameterless…
- The type of dictionary does not have a parameterless…
- Invalid assembly path. Doesn't contain directory information
- The property [ ] of type [ ] has no setter.
AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14).
Data as JSON: /api/errors/9f8fbce8d8e1e489.
Report an issue: GitHub.
Appendix: source
Thrown at sources/core/Stride.Core.Reflection/TypeDescriptors/SetDescriptor.cs:28
public class SetDescriptor : CollectionDescriptor
{
private static readonly List<string> ListOfMembersToRemove = ["Comparer", "Capacity"];
private Action<object, object?> addMethod;
private Action<object, object?> removeMethod;
private Action<object> clearMethod;
private Func<object, object?, bool> containsMethod;
private Func<object, int> countMethod;
private Func<object, bool> isReadOnlyMethod;
#pragma warning disable CS8618
// This warning is disabled because the necessary initialization will occur
// in the CreateSetDelegates<T>() method, not in the constructor.
public SetDescriptor(ITypeDescriptorFactory factory, Type type, bool emitDefaultValues, IMemberNamingConvention namingConvention)
: base(factory, type, emitDefaultValues, namingConvention)
{
if (!IsSet(type))
throw new ArgumentException("Expecting a type inheriting from System.Collections.ISet<T>", nameof(type));
HasAdd = true;
HasRemove = true;
HasIndexerAccessors = true;
HasInsert = false;
HasRemoveAt = false;
// extract Key, Value types from ISet<??>
var interfaceType = type.GetInterface(typeof(ISet<>))!;
var valueType = interfaceType.GetGenericArguments()[0];
// if the type has late bound generics, no delegates can be created as the type is invalid for calling collection operations
if (type.ContainsGenericParameters)
return;
var descriptorType = typeof(SetDescriptor).GetMethod(nameof(CreateSetDelegates), BindingFlags.NonPublic | BindingFlags.Instance)!.MakeGenericMethod([valueType]);
descriptorType.Invoke(this, []);
}View on GitHub (pinned to 96fad776d2)