Esporre la proprietà come variante in .NET per Interop

Sto creando una class wrapper in .NET (VB.NET come succede ma è ugualmente legata a C #) che è esposto a COM e una delle proprietà che sto cercando di avvolgere è una variante. Ho pensato di essere in grado di utilizzare un object, ma ottengo un errore:

Public Property FieldValue([vFieldID As Object = -1]) As Object non può essere esposto a COM come proprietà ‘Let’. Non sarà ansible assegnare valori non di object (come numeri o stringhe) a questa proprietà da Visual Basic 6.0 utilizzando un’istruzione “Let”. *

La mia dichiarazione di proprietà si presenta così:

 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 

La mia proprietà restituisce effettivamente un valore dal database che può essere intero, stringa, data, ecc. Quindi non è un object in termini di COM. C’è qualche soluzione a questo per consentire la proprietà Let?

COM Automation supporta una proprietà predefinita, la proprietà che ha dispid 0. Questo è usato nel codice VB6 con grande effetto, generando codice veramente compatto. Un tipico esempio è:

 rs!Customer = "foo" 

Quale è lo zucchero di syntax per:

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

Qui vengono utilizzate tre proprietà predefinite senza essere nominate nell’istruzione originale. L’interfaccia Recordset ha la proprietà Fields come proprietà predefinita, producendo un riferimento all’interfaccia Fields. Quale ha la proprietà Item come la proprietà predefinita (indicizzata) che produce un riferimento all’interfaccia Field. Quale ha la proprietà Value come proprietà predefinita, producendo una variante.

Che è molto carino Il prezzo dello zucchero sintetico estremo come questo è comunque la carie. C’è un’ambiguità di syntax in un’istruzione come:

 Dim obj obj = someObject 

Cosa si intende qui? Vuoi assegnare il riferimento someOggetto a obj? O vuoi assegnare la proprietà predefinita di someObject? Cose molto diverse, il tipo di object sarà completamente diverso. Questo è stato risolto in VB6 con la parola chiave Set . Se si desidera assegnare il riferimento all’object, è necessario scrivere:

 Set obj = someObject 

E tu ometti Set o usa Let esplicitamente se intendi assegnare il valore predefinito della proprietà. Questo è piuttosto schifoso e ha tormentato i principianti programmatori di Visual Basic e VB per molto tempo.

COM Automation implementa questo consentendo a una proprietà di avere due setter. Propput e propputref rispettivamente nell’IDL dove propputref è quello che assegna un object. È inoltre ansible visualizzare questo indietro nella definizione IDispatch, il metodo IDispatch :: Invoke () distingue tra i due con DISPATCH_PROPERTYPUT e DISPATCH_PROPERTYPUTREF.

Zip a VB.NET, Microsoft ha deciso che l’ambiguità era troppo dolorosa e ha eliminato la nozione di una proprietà predefinita non indicizzata. Che ha tranquillamente ritirato anche la parola chiave Set. Ciò tuttavia produce un nuovo problema, non c’è più modo di scrivere una class [ComVisible] che possa avere una proprietà di tipo Object con un setter che accetta un riferimento a un object. La syntax del linguaggio consente solo un setter e il livello di interoperabilità COM nel CLR manca l’impianto idraulico per sintetizzare due. Notevole è che questo è solo un avvertimento, si ottiene comunque il settaggio di propput, non si otterrà il setter propputref. Che per quanto posso dire è tutto ciò che vuoi comunque.

Definire l’interfaccia in una class dummy VB6 o scrivere esplicitamente l’IDL e compilarlo con midl.exe è in effetti un modo per aggirare l’avviso. Come mostrato da John Rivard in questa domanda .

Hai provato a utilizzare l’attributo MarshalAs ?

Dovresti essere in grado di applicarlo in quel modo (scusa se ho un errore di syntax, di solito uso C #):

 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 

Questo dovrebbe dire al marshaller di esporre la proprietà come una struttura VARIANT .

Potrebbe essere necessario applicare attributi aggiuntivi per le dimensioni della struttura, ecc., Ma penso che questa sia la direzione che è ansible utilizzare per risolvere il problema.