Exponer Propiedad como Variante en .NET para Interop

Estoy creando una clase contenedora en .NET (VB.NET, como ocurre, pero está igualmente relacionado con C #) que está expuesto a COM y una de las propiedades que estoy tratando de ajustar es una Variante. Pensé que solo podría usar un Objeto, pero me sale un error:

Public Property FieldValue([vFieldID As Object = -1]) As Object no se puede exponer a COM como una propiedad ‘Let’. No podrá asignar valores que no sean objetos (como números o cadenas) a esta propiedad desde Visual Basic 6.0 utilizando una instrucción ‘Let’. *

Mi statement de propiedad se ve así:

 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 

Mi propiedad realmente devuelve un valor de la base de datos que puede ser entero, cadena, fecha, etc. por lo que no es un objeto en términos de COM. ¿Hay alguna solución a esto para permitir la propiedad Let?

Automatización COM admite una propiedad predeterminada, la propiedad que tiene dispid 0. Esto se utiliza en el código VB6 con gran efecto, generando un código realmente compacto. Un ejemplo típico es:

 rs!Customer = "foo" 

¿Cuál es la syntax de azúcar para:

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

Aquí se usan tres propiedades predeterminadas sin nombre en la statement original. La interfaz Recordset tiene la propiedad Fields como la propiedad predeterminada, produciendo una referencia de interfaz Fields. Que tiene la propiedad Item como la propiedad predeterminada (indexada) que produce una referencia de interfaz de campo. Que tiene la propiedad Value como la propiedad predeterminada, produciendo una variante.

Lo cual es muy lindo Sin embargo, el precio del azúcar de syntax extrema como este es la caries dental. Hay una ambigüedad de syntax en una statement como:

 Dim obj obj = someObject 

¿Qué se pretende aquí? ¿Desea asignar la referencia someObject a obj? ¿O desea asignar la propiedad predeterminada de someObject? Muy diferentes cosas, el tipo obj será completamente diferente. Esto fue resuelto en VB6 con la palabra clave Set . Si desea asignar la referencia del objeto, debe escribir:

 Set obj = someObject 

Y omite Establecer o usa Detener explícitamente si quiere asignar el valor de propiedad predeterminado. Eso es bastante asqueroso y ha fastidiado a los novatos progtwigdores de scripts Visual Basic y VB durante mucho tiempo.

Automatización COM implementa esto permitiendo que una propiedad tenga dos setters. Respectivamente propputref y propputref en el IDL donde propputref es el que asigna un objeto. También puede ver esto en la definición de IDispatch, el método IDispatch :: Invoke () distingue entre los dos con DISPATCH_PROPERTYPUT y DISPATCH_PROPERTYPUTREF.

Zip forward a VB.NET, Microsoft decidió que la ambigüedad era demasiado dolorosa y eliminó la noción de una propiedad predeterminada no indexada. Que felizmente también retiró la palabra clave Establecer. Sin embargo, esto produce un nuevo problema, ya no hay forma de escribir una clase [ComVisible] que pueda tener una propiedad de tipo Object con un setter que acepte una referencia de objeto. La syntax del lenguaje permite solo un setter y la capa de interoperabilidad COM en el CLR le falta la plomería para sintetizar dos. Notable es que esto es solo una advertencia, todavía obtienes el setter de propput, simplemente no obtendrás el setter de propputref. Que, por lo que puedo decir, es todo lo que quieres de todos modos.

Definir la interfaz en una clase ficticia VB6 o escribir el IDL explícitamente y comstackrlo con midl.exe es una forma de sortear la advertencia. Como lo mostró John Rivard en esta pregunta .

¿ MarshalAs usar el atributo MarshalAs ?

Debería poder aplicarlo así (lo siento si tengo un error de syntax, suelo usar 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 

Eso debería decirle al marshaller que exponga la propiedad como una estructura VARIANT .

Puede que tenga que aplicar atributos adicionales para el tamaño de la estructura, etc., pero creo que esta es la dirección que puede usar para resolver su problema.