VSMEF010 ImportMany with unsupported collection type in constructor
When using [ImportMany] on a constructor parameter, only T[] (arrays) and IEnumerable<T> are supported as collection types.
Cause
A constructor parameter decorated with [ImportMany] uses a collection type other than array or IEnumerable<T>. While properties support additional collection types like List<T>, ICollection<T>, and custom collections, constructor parameters have stricter requirements.
Rule description
MEF needs to create the collection instance before passing it to the constructor. For constructor parameters, MEF only supports:
- Arrays (
T[]): MEF creates a new array IEnumerable<T>: MEF creates an array and passes it (arrays implementIEnumerable<T>)
Other collection types like List<T>, IList<T>, ICollection<T>, or custom collection types are not supported for constructor parameters because MEF cannot instantiate them appropriately.
For properties, MEF has more flexibility because it can either:
- Create the collection and assign it to the property
- Add items to an existing collection that was pre-initialized in the constructor
Examples of violations
List in constructor
using System.Collections.Generic;
using System.ComponentModel.Composition;
[Export]
class Service
{
[ImportingConstructor]
public Service([ImportMany] List<ILogger> loggers) // ❌ List<T> not supported
{
}
}
IList in constructor
using System.Collections.Generic;
using System.ComponentModel.Composition;
[Export]
class Service
{
[ImportingConstructor]
public Service([ImportMany] IList<ILogger> loggers) // ❌ IList<T> not supported
{
}
}
ICollection in constructor
using System.Collections.Generic;
using System.ComponentModel.Composition;
[Export]
class Service
{
[ImportingConstructor]
public Service([ImportMany] ICollection<ILogger> loggers) // ❌ ICollection<T> not supported
{
}
}
HashSet in constructor
using System.Collections.Generic;
using System.ComponentModel.Composition;
[Export]
class Service
{
[ImportingConstructor]
public Service([ImportMany] HashSet<ILogger> loggers) // ❌ HashSet<T> not supported
{
}
}
Valid scenarios (no diagnostic)
Array in constructor
using System.ComponentModel.Composition;
[Export]
class Service
{
[ImportingConstructor]
public Service([ImportMany] ILogger[] loggers) // ✅ OK
{
}
}
IEnumerable in constructor
using System.Collections.Generic;
using System.ComponentModel.Composition;
[Export]
class Service
{
[ImportingConstructor]
public Service([ImportMany] IEnumerable<ILogger> loggers) // ✅ OK
{
}
}
List on property (not constructor)
using System.Collections.Generic;
using System.ComponentModel.Composition;
[Export]
class Service
{
[ImportMany]
public List<ILogger> Loggers { get; set; } // ✅ OK for properties
}
Array of Lazy in constructor
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
[Export]
class Service
{
[ImportingConstructor]
public Service([ImportMany] Lazy<ILogger>[] loggers) // ✅ OK
{
}
}
IEnumerable of ExportFactory in constructor
using System.Collections.Generic;
using System.ComponentModel.Composition;
[Export]
class Service
{
[ImportingConstructor]
public Service([ImportMany] IEnumerable<ExportFactory<ILogger>> loggerFactories) // ✅ OK
{
}
}
How to fix violations
Option 1: Change to array type
// Before
[ImportingConstructor]
public Service([ImportMany] List<ILogger> loggers)
// After
[ImportingConstructor]
public Service([ImportMany] ILogger[] loggers)
Option 2: Change to IEnumerable
// Before
[ImportingConstructor]
public Service([ImportMany] List<ILogger> loggers)
// After
[ImportingConstructor]
public Service([ImportMany] IEnumerable<ILogger> loggers)
Option 3: Convert to List inside the constructor
If you need a List<T> for mutation, create it from the IEnumerable:
[Export]
class Service
{
private readonly List<ILogger> loggers;
[ImportingConstructor]
public Service([ImportMany] IEnumerable<ILogger> loggers)
{
this.loggers = loggers.ToList();
}
}
Option 4: Move to property import
If you need a specific collection type, use a property import instead:
[Export]
class Service
{
[ImportMany]
public List<ILogger> Loggers { get; set; } // Properties support more collection types
}
When to suppress warnings
This warning should not be suppressed as it indicates code that will fail at runtime during composition.