Generics were added in .NET 2.0 and COM existed before .NET 1.0.
(And was the technology .NET aimed to replace.)
COM never had generics, and therefore you cannot expose them.
Neither of COM languages (C++, VB6, Delphi) had generics so you can't expect them to be consumed.
(Well, C++ had templates but they are completely a different beast, and COM only meant interfaces.)
Exposing collections as an ArrayList
is the solution to this problem, you can't work around it.
Disclaimer: I am no expert on COM so the rest of the answer is roughly based on my guesses.
COM never “had” ArrayList
s, true, but so it never had any of the classes in .NET Framework, because it is not a framework itself. However, some of the .NET types get into the exported type libraries, and some don't. What about .NET Framework classes? Well, ArrayList
is [ComVisible]
, and List<T>
isn't.
Why?
COM works via interfaces, and the Interface Definition Language has no clue about generics and doesn't support them. Languages that support COM, such as VB6 or C++, wouldn't know what to do with the generics.
If there was a way to generate an interface for List<T>
, it would not contain T
in it so there is essentially no point in trying to expose a generic type. Possible imaginary alternatives to this would be:
- Generating a “specific” version of interface for a generic type, e.g.
IListOfString
for List<string>
- Erasing generic type information (much like Java does on compilation) and replacing
T
with object
.
The first option is not viable because the concrete T
type may not be known at compilation (read: Reflection), and List<T>
doesn't have a [ComVisible]
attribute on it anyway.
The second option is actually sort of possible because you can provide your own class interface with IList
and ICollection
properties:
[ComVisible(true)]
public interface IPerson
{
string Name { get;set;}
DateTime Entered { get;set;}
IList NickNamesList { get;}
ICollection NickNamesCollection { get;}
}
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.AutoDual)]
[ComDefaultInterface(typeof(IPerson))]
public class Person:IPerson
{
[ComVisible(false)]
public List<string> NickNames
{
get { return _NickNames; }
set { _NickNames = value; }
}
private List<string> _NickNames = new List<string>();
#region IPerson Members
IList IPerson.NickNamesList
{
get { return this.NickNames; }
}
ICollection IPerson.NickNamesCollection
{
get { return this.NickNames; }
}
#endregion
....
}
This is a workaround and doesn't answer your question though.
I am actually wondering if you could derive your StringList
class from List<string>
and mark it as [ComVisible(true)]
. You may want to check that.