Предоставление свойства как варианта в .NET для взаимодействия - PullRequest
8 голосов
/ 28 февраля 2012

Я создаю класс-оболочку в .NET (VB.NET, как это происходит, но в равной степени связан с C #), который доступен для COM, и одно из свойств, которое я пытаюсь обернуть, - это Variant. Я думал, что смогу использовать объект, но получаю ошибку:

Public Property FieldValue([vFieldID As Object = -1]) As Object не может быть выставлено COM как свойство 'Let'. Вы не сможете присвоить необъектным значениям (таким как числа или строки) этому свойству из Visual Basic 6.0 с помощью оператора «Let». *

Моя декларация выглядит следующим образом:

Public Property FieldValue(Optional ByVal vFieldID As Object = -1) As Object
    Get
        Return _objVAccess.FieldValue(vFieldID)
    End Get
    Set(ByVal value As Object)
        _objVAccess.FieldValue = value
    End Set
End Property

Мое свойство фактически возвращает значение из базы данных, которое может быть целым числом, строкой, датой и т. Д., Поэтому оно не является объектом с точки зрения COM. Есть ли обходной путь для разрешения свойства Let?

Ответы [ 2 ]

31 голосов
/ 29 марта 2012

COM Automation поддерживает свойство по умолчанию, свойство, которое имеет значение 0. Это очень полезно в коде VB6, генерируя действительно компактный код.Типичный пример:

rs!Customer = "foo"

Что является синтаксическим сахаром для:

rs.Fields.Item("Customer").Value = "foo"

Три свойства по умолчанию, которые используются здесь без имени в исходном операторе.Интерфейс Recordset имеет свойство Fields в качестве свойства по умолчанию, создавая ссылку на интерфейс Fields.Который имеет свойство Item как свойство по умолчанию (индексированное), создающее ссылку на интерфейс Field.Который имеет свойство Value как свойство по умолчанию, производя вариант.

Что очень хорошоОднако цена сахара с экстремальным синтаксисом, подобного этому, - это разрушение зубов.Синтаксическая неоднозначность в выражении типа:

Dim obj  
obj = someObject

Что здесь подразумевается?Вы хотите назначить ссылку на someObject для obj?Или вы хотите назначить свойство по умолчанию для someObject?Совсем разные вещи, тип obj будет совершенно другим.Это было решено в VB6 с ключевым словом Set .Если вы хотите присвоить ссылку на объект, вам нужно написать:

Set obj = someObject

И вы опускаете Установить или используете Позвольте явно, если вы хотите назначить значение по умолчаниюстоимость имущества.Это довольно отвратительно и очень долго мешало начинающим программистам на Visual Basic и VB.

COM Automation реализует это, позволяя свойству иметь два сеттера.Соответственно propput и propputref в IDL, где propputref - это тот, который назначает объект.Вы также можете увидеть это в определении IDispatch, метод IDispatch :: Invoke () различает два с помощью DISPATCH_PROPERTYPUT и DISPATCH_PROPERTYPUTREF.

Зайдите в VB.NET, Microsoft решила, что неоднозначность была слишком болезненной, иисключено понятие неиндексированного свойства по умолчанию.Который блаженно также удалил ключевое слово Set.Это, однако, порождает новую проблему: больше нет способа написать класс [ComVisible], который может иметь свойство типа Object с установщиком, который принимает ссылку на объект.Синтаксис языка допускает только один установщик, а на уровне взаимодействия COM в CLR отсутствует канализация для синтеза двух.Примечательно, что это всего лишь предупреждение, вы все равно получаете установщик проппута, вы просто не получите установщик проппутрефа.Что, насколько я могу судить, это все, что вам нужно в любом случае.

Определение интерфейса либо в фиктивном классе VB6, либо путем явной записи IDL и компиляции его с помощью midl.exe - действительно способ обойти предупреждение,Как показал Джон Ривард в этот вопрос .

3 голосов
/ 02 марта 2012

Вы пытались использовать атрибут MarshalAs?

Вы должны иметь возможность применять его таким образом (извините, если у меня есть синтаксическая ошибка, я обычно использую C #):

Public Property FieldValue(Optional ByVal vFieldID As Object = -1) As <MarshalAsAttribute(UnmanagedType.Struct)> Object
    Get  
        Return _objVAccess.FieldValue(vFieldID)  
    End Get  
    Set(ByVal value As Object)  
        _objVAccess.FieldValue = value  
    End Set  
End Property

Это должно сказать маршаллеру выставить свойство как VARIANT структуру.

Возможно, вам придется применить дополнительные атрибуты для размера структуры и т. Д., Но я думаю, что это направление, которое вы можете использовать для решения своей проблемы.

...