Почему ArrayList работает с COM Interop, а IList <T>- нет? - PullRequest
7 голосов
/ 10 августа 2011

Я заметил, что если я создаю компонент .NET, который предоставляет ArrayList, то этот ArrayList проходит через COM Interop и доступен на скриптовых языках, таких как VBScript.похоже, не работает.

Почему это так, и есть ли способ, чтобы универсальный тип успешно передавался через COM Interop в механизм сценариев?

1 Ответ

6 голосов
/ 10 августа 2011

Обобщения были добавлены в .NET 2.0, а COM существовал до .NET 1.0.
(И была технология .NET , предназначенная для замены .)

COM никогда не имел обобщения,и, следовательно, вы не можете их выставить.
Ни у одного из языков COM (C ++, VB6, Delphi) не было обобщений, поэтому вы не можете ожидать, что они будут использованы.
(Ну, у C ++ были шаблоны, но они совершенно другой зверьи COM означает только интерфейсы .)

Предоставление коллекций в виде ArrayList является решением для этой проблемы, вы не можетеобойти это.

Отказ от ответственности : я не эксперт по COM, поэтому остальная часть ответа примерно основана на моих догадках.

COMникогда не «имел» ArrayList с, правда, но поэтому никогда не было любых классов в .NET Framework, потому что это не сама платформа.Однако некоторые из типов .NET попадают в экспортируемые библиотеки типов, а некоторые - нет.А как насчет классов .NET Framework?Ну, ArrayList - это [ComVisible], а List<T> - нет.

Почему?

COM работает через интерфейсы , а язык определения интерфейсов не имеет представления о дженериках и не поддерживает их.Языки, которые поддерживают COM, такие как VB6 или C ++, не будут знать, что делать с универсальными шаблонами.

Если бы был способ создать интерфейс для List<T>, он не содержат T в нем, так что нет смысла пытаться раскрыть универсальный тип.Возможные мнимые альтернативы этому:

  • Генерация «определенной» версии интерфейса для универсального типа, например, IListOfString для List<string>
  • Стирание информации универсального типа (значительнокак Java это делает при компиляции) и заменой T на object.

Первый вариант недопустим, поскольку конкретный тип T может быть неизвестен при компиляции (читай: Reflection),и List<T> все равно не имеет атрибута [ComVisible].

Второй вариант фактически возможен, потому что вы можете предоставить свой собственный интерфейс класса с IList и ICollectionproperties :

[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
    ....
}

Это обходной путь, но он не отвечает на ваш вопрос.

Мне действительно интересно, могли бы вы получить класс StringList из List<string>и отметьте его как [ComVisible(true)].Вы можете проверить это.

...