Why does ArrayList work with COM Interop, but IList <T> is not?

I noticed that if I create a .NET component that provides an ArrayList, then this ArrayList goes through COM Interop and is available in scripts like VBScript.

Generics like IList<T> don't seem to work.

Why is this and is there a way to make the generic type successfully flow through COM Interop into the script engine?

+6
generics scripting com-interop
source share
1 answer

Generics were added in .NET 2.0 and COM existed before .NET 1.0.
(And there was .NET technology designed to replace it.)

COM has never had generics, and therefore you cannot expose them.
None of the COM languages ​​(C ++, VB6, Delphi) had generics, so you cannot expect their consumption.
(Well, C ++ had templates, but they are completely different beasts, and COM are just interfaces.)

Providing collections as an ArrayList is a solution to this problem, you cannot get around it.

Disclaimer I'm not a COM expert, so the rest of the answer is roughly based on my guesses.

COM never "had" ArrayList s, true, but therefore it never had any of the classes in the .NET Framework, because it is not the infrastructure itself. However, some .NET types fall into exported type libraries, and some do not. What about the .NET Framework classes? Well, ArrayList is [ComVisible] , but List<T> is not.

Why?

COM works through interfaces , and the interface definition language has no idea about generics and does not support them. Languages ​​that support COM, such as VB6 or C ++, did not know what to do with generics.

If there was a way to create an interface for List<T> , it would not contain T in it, so it makes no sense to try to set a common type. Possible alternatives may include the following:

  • Creating a β€œconcrete” version of an interface for a generic type, for example. IListOfString for List<string>
  • Removing general type information (similar to how Java does it when compiling) and replacing T with object .

The first option is not viable, since the specific type of T cannot be known at compilation (read: Reflection), and List<T> does not have the [ComVisible] attribute on it.

The second option is really 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 does not answer your question.

I'm really curious to know if it is possible to derive the StringList class from List<string> and mark it as [ComVisible(true)] . You can check it out.

+5
source share

All Articles